Visual3D.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media3D / Visual3D.cs / 1 / Visual3D.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (c) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
// 
// History:
//  6/8/2005 : [....] - Created 
//
//---------------------------------------------------------------------------

using MS.Internal; 
using MS.Internal.Media;
using MS.Internal.Media3D; 
using MS.Internal.PresentationCore; 
using System;
using System.Diagnostics; 
using System.Security;
using System.Windows.Media.Composition;
using System.Windows.Media;
 
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 
 
namespace System.Windows.Media.Media3D
{ 
    /// 
    ///     Visual3D is the base class for all 3D visual elements.
    /// 
    public abstract partial class Visual3D : DependencyObject, DUCE.IResource, IVisual3DContainer 
    {
        // ------------------------------------------------------------------- 
        // 
        //   Constants
        // 
        // -------------------------------------------------------------------

        #region Constants
 
        /// 
        /// This is the dirty mask for a visual, set every time we marshall 
        /// a visual to a channel and reset by the end of the render pass. 
        /// 
        private const VisualProxyFlags c_Model3DVisualProxyFlagsDirtyMask = 
              VisualProxyFlags.IsSubtreeDirtyForRender
            | VisualProxyFlags.IsContentDirty
            | VisualProxyFlags.IsTransformDirty;
 
        #endregion Constants
 
        //------------------------------------------------------ 
        //
        //  Constructors 
        //
        //-----------------------------------------------------

        #region Constructors 

        // Prevent 3rd parties from extending this abstract base class. 
        internal Visual3D() 
        {
            _internalIsVisible = true; 
        }

        #endregion Constructors
 

        // -------------------------------------------------------------------- 
        // 
        //   IResource implementation
        // 
        // --------------------------------------------------------------------

        #region IResource implementation
 
        /// 
        /// This is used to check if the composition node 
        /// for the visual is on channel 
        /// 
        ///  
        /// 
        internal bool IsOnChannel(DUCE.Channel channel)
        {
            return _proxy.IsOnChannel(channel); 
        }
 
        ///  
        /// Returns the handle this visual has on the given channel.
        ///  
        /// 
        /// 
        DUCE.ResourceHandle DUCE.IResource.GetHandle(DUCE.Channel channel)
        { 
            return _proxy.GetHandle(channel);
        } 
 
        /// 
        /// Returns the handle this visual has on the given channel. 
        /// Note: The 3D handle is the normal handle for Visual3D
        /// 
        DUCE.ResourceHandle DUCE.IResource.Get3DHandle(DUCE.Channel channel)
        { 
            return _proxy.GetHandle(channel);
        } 
 
        /// 
        /// This is used to create or addref the visual resource 
        /// on the given channel
        /// 
        /// 
        ///  
        DUCE.ResourceHandle DUCE.IResource.AddRefOnChannel(DUCE.Channel channel)
        { 
            _proxy.CreateOrAddRefOnChannel(channel, DUCE.ResourceType.TYPE_VISUAL3D); 

            return _proxy.GetHandle(channel); 
        }

        /// 
        /// Sends a command to compositor to remove the child 
        /// from its parent on the channel.
        ///  
        void DUCE.IResource.RemoveChildFromParent( 
                DUCE.IResource parent,
                DUCE.Channel channel) 
        {
            DUCE.Visual3DNode.RemoveChild(
                parent.Get3DHandle(channel),
                _proxy.GetHandle(channel), 
                channel);
        } 
 
        int DUCE.IResource.GetChannelCount()
        { 
            return _proxy.Count;
        }

        DUCE.Channel DUCE.IResource.GetChannel(int index) 
        {
            return _proxy.GetChannel(index); 
        } 

        #endregion IResource implementation 


        //-----------------------------------------------------
        // 
        //  Public Methods
        // 
        //------------------------------------------------------ 

        #region Public Methods 

        /// 
        ///    DependencyProperty which backs the ModelVisual3D.Transform property.
        ///  
        public static readonly DependencyProperty TransformProperty =
            DependencyProperty.Register( 
                    "Transform", 
                    /* propertyType = */ typeof(Transform3D),
                    /* ownerType = */ typeof(Visual3D), 
                    new PropertyMetadata(Transform3D.Identity, TransformPropertyChanged),
                    (ValidateValueCallback) delegate { return MediaContext.CurrentMediaContext.WriteAccessEnabled; });

        private static void TransformPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Visual3D owner = ((Visual3D) d); 
 
            if (!e.IsASubPropertyChange)
            { 
                if (e.OldValue != null)
                {
                    owner.DisconnectAttachedResource(
                        VisualProxyFlags.IsTransformDirty, 
                        ((DUCE.IResource) e.OldValue));
                } 
 
                owner.SetFlagsOnAllChannels(true, VisualProxyFlags.IsTransformDirty);
            } 

            // NTRAID#Longhorn-1614112-2006/05/25-[....] - Stop over-invalidating _bboxSubgraph
            //
            // We currently maintain a cache of both a ModelVisual3D’s content 
            // and subgraph bounds.  A better solution that would be both a 2D
            // and 3D win would be to stop invalidating _bboxSubgraph when a 
            // visual’s transform changes. 
            owner.RenderChanged(/* sender = */ owner, EventArgs.Empty);
        } 

        /// 
        ///     Transform for this Visual3D.
        ///  
        public Transform3D Transform
        { 
            get 
            {
                return (Transform3D) GetValue(TransformProperty); 
            }

            set
            { 
                SetValue(TransformProperty, value);
            } 
        } 

        #endregion Public Methods 

        //-----------------------------------------------------
        //
        //  Public Properties 
        //
        //----------------------------------------------------- 
 
        //-----------------------------------------------------
        // 
        //  Public Events
        //
        //------------------------------------------------------
 
        //-----------------------------------------------------
        // 
        //  Protected Methods 
        //
        //------------------------------------------------------ 

        #region Protected Methods

        ///  
        /// AttachChild
        /// 
        ///    Derived classes must call this method to notify the Visual3D layer that a new 
        ///    child appeard in the children collection. The Visual3D layer will then call the GetVisual3DChild
        ///    method to find out where the child was added. 
        ///
        ///  Remark: To move a Visual3D child in a collection it must be first disconnected and then connected
        ///    again. (Moving forward we might want to add a special optimization there so that we do not
        ///    unmarshal our composition resources). 
        /// 
        protected void AddVisual3DChild(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 == null); 

            child.SetParent(this); 

            // set the inheritance context so databinding, etc... work
            ProvideSelfAsInheritanceContext(child, null);
 
            // The child already might be dirty. Hence we need to propagate dirty information
            // from the parent and from the child. 
            Visual3D.PropagateFlags( 
                this,
                VisualFlags.IsSubtreeDirtyForPrecompute, 
                VisualProxyFlags.IsSubtreeDirtyForRender);

            Visual3D.PropagateFlags(
                child, 
                VisualFlags.IsSubtreeDirtyForPrecompute,
                VisualProxyFlags.IsSubtreeDirtyForRender); 
 
            //
 

            // Fire notifications
            OnVisualChildrenChanged(child, /* visualRemoved = */ null);
 
            child.FireOnVisualParentChanged(null);
        } 
 

        ///  
        /// 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.
        /// 
        ///  
        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)) 
                {
                    channel.AddToRemoveAndReleaseQueue( 
                        this,
                        child);

                    child.SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent); 
                }
            } 
 
            //
            // 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);
        } 
 
        /// 
        ///    The InternalIsVisible property roughly corresponds to the Opacity in the Visual world. 
        ///    When it is set to true, then the actual transform used for this visual on the MIL side
        ///    is set to a zero scale transform.  This makes the object invisible.
        /// 
        internal bool InternalIsVisible 
        {
            get 
            { 
                return _internalIsVisible;
            } 
            set
            {
                if (_internalIsVisible != value)
                { 
                    // if we're going from Not Visible -> Visibile remove the zero scale from the Channel
                    // otherwise remove the user's transform 
                    if (value) 
                    {
                        DisconnectAttachedResource( 
                            VisualProxyFlags.IsTransformDirty,
                            ((DUCE.IResource)_zeroScale));
                    }
                    else 
                    {
                        Transform3D transform = Transform; 
 
                        if (transform != null)
                        { 
                            DisconnectAttachedResource(
                                VisualProxyFlags.IsTransformDirty,
                                ((DUCE.IResource)transform));
                        } 
                    }
 
                    SetFlagsOnAllChannels(true, VisualProxyFlags.IsTransformDirty); 

                    RenderChanged(/* sender = */ this, EventArgs.Empty); 

                    _internalIsVisible = value;
                }
            } 
        }
 
        // isSubpropertyChange indicates whether a subproperty on Visual3DModel changed. 
        // In this case oldValue is ignored, since the value hasn't changed.  If it isn't a
        // sub property change, then oldValue gives the previous value of the Visual3DModel property. 
        private void Visual3DModelPropertyChanged(Model3D oldValue, bool isSubpropertyChange)
        {
            if (!isSubpropertyChange)
            { 
                if (oldValue != null)
                { 
                    DisconnectAttachedResource(VisualProxyFlags.IsContentDirty, 
                                               oldValue);
                } 

                SetFlagsOnAllChannels(true, VisualProxyFlags.IsContentDirty);
            }
 
            SetFlags(false, VisualFlags.Are3DContentBoundsValid);
 
            RenderChanged(/* sender = */ this, EventArgs.Empty); 
        }
 
        private void Visual3DModelPropertyChanged(object o, EventArgs e)
        {
            // forward on to the main property changed method.  Since this method is
            // only called on subproperty chanes, oldValue is meaningless. 
            Visual3DModelPropertyChanged(null, /* isSubpropertyChange = */ true);
        } 
 
        /// 
        ///     The Model3D to render 
        /// 
        protected Model3D Visual3DModel
        {
            get 
            {
                VerifyAPIReadOnly(); 
 
                return _visual3DModel;
            } 

            set
            {
                VerifyAPIReadWrite(); 

                if (value != _visual3DModel) 
                { 
                    // remove the old change listener
                    if (_visual3DModel != null && !_visual3DModel.IsFrozenInternal) 
                    {
                        _visual3DModel.ChangedInternal -= Visual3DModelPropertyChanged;
                    }
 
                    // notify of the property change
                    Visual3DModelPropertyChanged(_visual3DModel, /* isSubpropertyChange = */ false); 
                    _visual3DModel = value; 

                    // set the new one 
                    if (_visual3DModel != null && !_visual3DModel.IsFrozenInternal)
                    {
                        _visual3DModel.ChangedInternal += Visual3DModelPropertyChanged;
                    } 
                }
            } 
        } 

        ///  
        /// This is called when the parent link of the Visual is changed.
        /// This method executes important base functionality before calling the
        /// overridable virtual.
        ///  
        /// Old parent or null if the Visual did not have a parent before.
        internal virtual void FireOnVisualParentChanged(DependencyObject oldParent) 
        { 
            // Call the ParentChanged virtual before firing the Ancestor Changed Event
            OnVisualParentChanged(oldParent); 

            // If we are attaching to a tree then
            // send the bit up if we need to.
            if (oldParent == null) 
            {
                Debug.Assert(VisualTreeHelper.GetParent(this) != null, "If oldParent is null, current parent should != null."); 
 
                if(CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                { 
                    Visual.SetTreeBits(
                        VisualTreeHelper.GetParent(this),
                        VisualFlags.SubTreeHoldsAncestorChanged,
                        VisualFlags.RegisteredForAncestorChanged); 
                }
            } 
            // If we are cutting a sub tree off then 
            // clear the bit in the main tree above if we need to.
            else 
            {
                if (CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                {
                    Visual.ClearTreeBits( 
                        oldParent,
                        VisualFlags.SubTreeHoldsAncestorChanged, 
                        VisualFlags.RegisteredForAncestorChanged); 
                }
            } 

            // Fire the Ancestor changed Event on the nodes.
            AncestorChangedEventArgs args = new AncestorChangedEventArgs(this, oldParent);
            ProcessAncestorChangedNotificationRecursive(this, args); 
        }
 
        ///  
        ///   Add removed delegates to the VisualAncenstorChanged Event.
        ///  
        /// 
        ///     This also sets/clears the tree-searching bit up the tree
        /// 
        internal event Visual.AncestorChangedEventHandler VisualAncestorChanged 
        {
            add 
            { 
                Visual.AncestorChangedEventHandler newHandler = AncestorChangedEventField.GetValue(this);
 
                if (newHandler == null)
                {
                    newHandler = value;
                } 
                else
                { 
                    newHandler += value; 
                }
 
                AncestorChangedEventField.SetValue(this, newHandler);

                Visual.SetTreeBits(
                    this, 
                    VisualFlags.SubTreeHoldsAncestorChanged,
                    VisualFlags.RegisteredForAncestorChanged); 
            } 

            remove 
            {
                // check that we are Disabling a node that was previously Enabled
                if(CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                { 
                    Visual.ClearTreeBits(
                                        this, 
                                        VisualFlags.SubTreeHoldsAncestorChanged, 
                                        VisualFlags.RegisteredForAncestorChanged);
                } 

                // if we are Disabling a Visual that was not Enabled then this
                // search should fail.  But it is safe to check.
                Visual.AncestorChangedEventHandler newHandler = AncestorChangedEventField.GetValue(this); 

                if (newHandler != null) 
                { 
                    newHandler -= value;
 
                    if(newHandler == null)
                    {
                        AncestorChangedEventField.ClearValue(this);
                    } 
                    else
                    { 
                        AncestorChangedEventField.SetValue(this, newHandler); 
                    }
                } 
            }
        }

        ///  
        ///     Walks down in the tree for nodes that have AncestorChanged Handlers
        ///     registered and calls them. 
        ///     It uses Flag bits that help it prune the walk.  This should go 
        ///     straight to the relevent nodes.
        ///  
        internal static void ProcessAncestorChangedNotificationRecursive(DependencyObject e, AncestorChangedEventArgs args)
        {
            if (e is Visual)
            { 
                Visual.ProcessAncestorChangedNotificationRecursive(e, args);
            } 
            else 
            {
                Visual3D eAsVisual3D = e as Visual3D; 

                // If the flag is not set, then we are Done.
                if(!eAsVisual3D.CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                { 
                    return;
                } 
 
                // If there is a handler on this node, then fire it.
                Visual.AncestorChangedEventHandler handler = AncestorChangedEventField.GetValue(eAsVisual3D); 

                if(handler != null)
                {
                    handler(eAsVisual3D, args); 
                }
 
                // Decend into the children. 
                int count = eAsVisual3D.InternalVisual2DOr3DChildrenCount;
                for (int i = 0; i < count; i++) 
                {
                    DependencyObject child = eAsVisual3D.InternalGet2DOr3DVisualChild(i);
                    if (child != null)
                    { 
                        Visual3D.ProcessAncestorChangedNotificationRecursive(child, args);
                    } 
                } 
            }
        } 


        /// 
        /// OnVisualParentChanged is called when the parent of the Visual is changed. 
        /// 
        /// Old parent or null if the Visual did not have a parent before. 
        protected internal virtual void OnVisualParentChanged(DependencyObject oldParent) 
        {
        } 

        /// 
        /// OnVisualChildrenChanged is called when the VisualCollection of the Visual is edited.
        ///  
        protected internal virtual void OnVisualChildrenChanged(
            DependencyObject visualAdded, 
            DependencyObject visualRemoved) 
        {
        } 

        #endregion Protected Methods

        //------------------------------------------------------ 
        //
        //  Internal Methods 
        // 
        //-----------------------------------------------------
 
        #region Internal Methods

        internal bool DoesRayHitSubgraphBounds(RayHitTestParameters rayParams)
        { 
            Point3D origin;
            Vector3D direction; 
            rayParams.GetLocalLine(out origin, out direction); 

            Rect3D bboxSubgraph = VisualDescendantBounds; 
            return LineUtil.ComputeLineBoxIntersection(ref origin, ref direction, ref bboxSubgraph, rayParams.IsRay);
        }

        ///  
        /// Initiate a hit test using delegates.
        ///  
        internal void HitTest( 
            HitTestFilterCallback filterCallback,
            HitTestResultCallback resultCallback, 
            HitTestParameters3D hitTestParameters)
        {
            if (resultCallback == null)
            { 
                throw new ArgumentNullException("resultCallback");
            } 
 
            if (hitTestParameters == null)
            { 
                throw new ArgumentNullException("hitTestParameters");
            }

            VerifyAPIReadWrite(); 

            RayHitTestParameters rayParams = hitTestParameters as RayHitTestParameters; 
 
            if (rayParams != null)
            { 
                // In case the user is reusing the same RayHitTestParameters
                rayParams.ClearResults();

                HitTestResultBehavior result = RayHitTest(filterCallback, rayParams); 

                rayParams.RaiseCallback(resultCallback, filterCallback, result); 
            } 
            else
            { 
                // This should never happen, users can not extend the abstract HitTestParameters3D class.
                Invariant.Assert(false,
                    String.Format(System.Globalization.CultureInfo.InvariantCulture,
                        "'{0}' HitTestParameters3D are not supported on {1}.", 
                        hitTestParameters.GetType().Name, this.GetType().Name));
            } 
        } 

        internal HitTestResultBehavior RayHitTest( 
            HitTestFilterCallback filterCallback,
            RayHitTestParameters rayParams)
        {
            if (DoesRayHitSubgraphBounds(rayParams)) 
            {
                // 
                // Determine if there is a special filter behavior defined for this 
                // Visual.
                // 

                HitTestFilterBehavior behavior = HitTestFilterBehavior.Continue;

                if (filterCallback != null) 
                {
                    behavior = filterCallback(this); 
 
                    if (HTFBInterpreter.SkipSubgraph(behavior)) return HitTestResultBehavior.Continue;
                    if (HTFBInterpreter.Stop(behavior)) return HitTestResultBehavior.Stop; 
                }

                //
                // Hit test against the children. 
                //
 
                if (HTFBInterpreter.IncludeChildren(behavior)) 
                {
                    HitTestResultBehavior result = HitTestChildren(filterCallback, rayParams); 

                    if (result == HitTestResultBehavior.Stop) return HitTestResultBehavior.Stop;
                }
 
                //
                // Hit test against the content of this Visual. 
                // 

                if (HTFBInterpreter.DoHitTest(behavior)) 
                {
                    RayHitTestInternal(filterCallback, rayParams);
                }
            } 

            return HitTestResultBehavior.Continue; 
        } 

        internal HitTestResultBehavior HitTestChildren( 
            HitTestFilterCallback filterCallback,
            RayHitTestParameters rayParams)
        {
            return HitTestChildren(filterCallback, rayParams, this); 
        }
 
        ///  
        ///     Static helper used by ModelVisual3D and Viewport3DVisual to hit test
        ///     against their children collections. 
        /// 
        internal static HitTestResultBehavior HitTestChildren(
            HitTestFilterCallback filterCallback,
            RayHitTestParameters rayParams, 
            IVisual3DContainer container)
        { 
            if (container != null) 
            {
                int childrenCount = container.GetChildrenCount(); 

                for (int i = childrenCount - 1; i >= 0; i--)
                {
                    Visual3D child = container.GetChild(i); 

                    // Visuall3D.RayHitTest does not apply the Visual3D's Transform.  We need to 
                    // transform into the content's space before hit testing. 
                    Transform3D transform = child.Transform;
                    rayParams.PushVisualTransform(transform); 

                    // Perform the hit-test against the child.
                    HitTestResultBehavior result = child.RayHitTest(filterCallback, rayParams);
 
                    rayParams.PopTransform(transform);
 
                    if (result == HitTestResultBehavior.Stop) 
                    {
                        return HitTestResultBehavior.Stop; 
                    }
                }
            }
 
            return HitTestResultBehavior.Continue;
        } 
 
        internal void RayHitTestInternal(
            HitTestFilterCallback filterCallback, 
            RayHitTestParameters rayParams)
        {
            Model3D model = _visual3DModel;
 
            if (model != null)
            { 
                // If our Model3D hit test intersects anything we should return "this" Visual3D 
                // as the HitTestResult.VisualHit.
                rayParams.CurrentVisual = this; 

                model.RayHitTest(rayParams);
            }
        } 

        ///  
        ///     Generic "render changed" handler which sets IsDirtyForRender 
        ///     and propagates IsSubtreeDirtyForRender/Precompute.
        ///  
        internal void RenderChanged(object sender, EventArgs e)
        {
            PropagateFlags(
                this, 
                VisualFlags.IsSubtreeDirtyForPrecompute,
                VisualProxyFlags.IsSubtreeDirtyForRender); 
        } 

        ///  
        /// VisualContentBounds returns the bounding box for the contents of the current visual.
        /// 
        internal Rect3D VisualContentBounds
        { 
            get
            { 
                // Probably too restrictive. Let's see who wants it during OnRender. 
                VerifyAPIReadWrite();
 
                return GetContentBounds();
            }
        }
 
        /// 
        /// Visual2DContentBounds returns the 2D bounding box for the content of this 3D object.  The 2D bounding box 
        /// is the projection of the 3D content bounding box up to the nearest 2D visual that contains the Visual3D. 
        /// 
        [FriendAccessAllowed] 
        internal Rect Visual2DContentBounds
        {
            get
            { 
                VerifyAPIReadWrite();
                Rect contentBounds = Rect.Empty; 
 
                Viewport3DVisual viewport3DVisual = (Viewport3DVisual)VisualTreeHelper.GetContainingVisual2D(this);
                if (viewport3DVisual != null) { 
                    GeneralTransform3DTo2D transform = TransformToAncestor(viewport3DVisual);
                    contentBounds = transform.TransformBounds(VisualContentBounds);
                }
 
                return contentBounds;
            } 
        } 

        // Returns true if the content has something requiring realization 
        internal bool PrecomputeContent()
        {
            Model3D model = _visual3DModel;
            if (model != null) 
            {
                // The Visual3D may be dirty for precompute because of its 
                // children not because of its Content so we'll check before 
                // calling
                if (model._flags[Model3D.DirtyForPreComputeFlag]) 
                {
                    model.PreCompute();
                }
 
                return model._flags[Model3D.RequiresRealizationFlag];
            } 
 
            return false;
        } 

        internal Rect3D BBoxSubgraph
        {
            get 
            {
                if (CheckFlagsAnd(VisualFlags.IsSubtreeDirtyForPrecompute)) 
                { 
                    // force an update of the bounds cache
                    Rect3D transformedBBoxSubgraphIgnored; 
                    PrecomputeRecursive(out transformedBBoxSubgraphIgnored);
                }

                Debug_VerifyCachedSubgraphBounds(); 

                return _bboxSubgraph; 
            } 

        } 

        /// 
        /// Derived classes must override this method and return the bounding
        /// box of their content in the Visual's local space. 
        /// 
        internal Rect3D GetContentBounds() 
        { 
            Model3D model = _visual3DModel;
 
            if (model == null)
            {
                return Rect3D.Empty;
            } 

            if (!CheckFlagsAnd(VisualFlags.Are3DContentBoundsValid)) 
            { 
                _bboxContent = model.CalculateSubgraphBoundsOuterSpace();
                SetFlags(true, VisualFlags.Are3DContentBoundsValid); 
            }

            Debug_VerifyCachedContentBounds();
 
            return _bboxContent;
        } 
 
        /// 
        /// Returns the subgraph bounds in the Visual3D's outer coordinate space. 
        /// 
        internal Rect3D CalculateSubgraphBoundsOuterSpace()
        {
            Rect3D bounds = CalculateSubgraphBoundsInnerSpace(); 

            return M3DUtil.ComputeTransformedAxisAlignedBoundingBox(ref bounds, Transform); 
        } 

        ///  
        /// Returns the subgraph bounds in the Visual3D's inner coordinate space.
        /// 
        internal Rect3D CalculateSubgraphBoundsInnerSpace()
        { 
            return BBoxSubgraph;
        } 
 
        /// 
        /// VisualDescendantBounds returns the union of all of the content bounding 
        /// boxes for all of the descendants of the current visual, but not including
        /// the contents of the current visual.
        /// 
        internal Rect3D VisualDescendantBounds 
        {
            get 
            { 
                // Probably too restrictive. Let's see who wants it during OnRender.
                VerifyAPIReadWrite(); 

                return CalculateSubgraphBoundsInnerSpace();
            }
        } 

        // CS0536: Intreface implementation must be public or explicit so we re-expose 
        // the internal methods as an explicit implementation of an internal interface. 
        void IVisual3DContainer.VerifyAPIReadOnly() { this.VerifyAPIReadOnly(); }
        void IVisual3DContainer.VerifyAPIReadOnly(DependencyObject other) { this.VerifyAPIReadOnly(other); } 
        void IVisual3DContainer.VerifyAPIReadWrite() { this.VerifyAPIReadWrite(); }
        void IVisual3DContainer.VerifyAPIReadWrite(DependencyObject other) { this.VerifyAPIReadWrite(other); }

        ///  
        /// Applies various API checks
        ///  
        internal void VerifyAPIReadOnly() 
        {
            // Verify that we are executing on the right context 
            VerifyAccess();
        }

        ///  
        /// Applies various API checks
        ///  
        internal void VerifyAPIReadOnly(DependencyObject other) 
        {
            VerifyAPIReadOnly(); 

            if (other != null)
            {
                // Make sure the visual is on the same context as we are 
                MediaSystem.AssertSameContext(this, other);
            } 
        } 

        ///  
        /// Applies various API checks for read/write
        /// 
        internal void VerifyAPIReadWrite()
        { 
            VerifyAPIReadOnly();
 
            // Verify the correct access permissions 
            MediaContext.From(this.Dispatcher).VerifyWriteAccess();
        } 

        /// 
        /// Applies various API checks
        ///  
        internal void VerifyAPIReadWrite(DependencyObject other)
        { 
            VerifyAPIReadWrite(); 

            if (other != null) 
            {
                // Make sure the visual is on the same context as we are
                MediaSystem.AssertSameContext(this, other);
            } 
        }
 
        internal void SetParent(Visual newParent) 
        {
            _2DParent.SetValue(this, newParent); 
            _3DParent = null;

            Debug.Assert(InternalVisualParent == newParent);
        } 

        internal void SetParent(Visual3D newParent) 
        { 
            _2DParent.ClearValue(this);
            _3DParent = newParent; 

            Debug.Assert(InternalVisualParent == newParent);
        }
 
        /// 
        ///  Derived classes override this property to enable the Visual code to enumerate 
        ///  the Visual children. Derived classes need to return the number of children 
        ///  from this method.
        /// 
        ///    By default a Visual does not have any children.
        ///
        ///  Remark: During this virtual method the Visual tree must not be modified.
        ///  
        protected virtual int Visual3DChildrenCount
        { 
            get { return 0; } 
        }
 
        /// 
        ///   Derived class must implement to support Visual children. The method must return
        ///    the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1.
        /// 
        ///    By default a Visual does not have any children.
        /// 
        ///  Remark: 
        ///       Need to lock down Visual tree during the callbacks.
        ///       During this virtual call it is not valid to modify the Visual tree. 
        ///
        ///       It is okay to type this protected API to the 2D Visual.  The only 2D Visual with
        ///       3D childern is the Viewport3DVisual which is sealed.  -- [....] 01/17/06
        ///  
        protected virtual Visual3D GetVisual3DChild(int index)
        { 
           throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); 
        }
 
        /// 
        ///     Notifies the element that you have added a child.  The Element
        ///     will update the parent pointer, fire the correct events, etc.
        ///  
        void IVisual3DContainer.AddChild(Visual3D child)
        { 
            AddVisual3DChild(child); 
        }
 
        /// 
        ///     Notifies the element that you have removed a child.  The Element
        ///     will update the parent pointer, fire the correct events, etc.
        ///  
        void IVisual3DContainer.RemoveChild(Visual3D child)
        { 
            RemoveVisual3DChild(child); 
        }
 
        /// 
        ///     Gets the number of Visual3D children that the IVisual3DContainer
        ///     contains.
        ///  
        int IVisual3DContainer.GetChildrenCount()
        { 
            return Visual3DChildrenCount; 
        }
 
        /// 
        ///     Gets the index children of the IVisual3DContainer
        /// 
        Visual3D IVisual3DContainer.GetChild(int index) 
        {
            return GetVisual3DChild(index); 
        } 

        //------------------------------------------------------ 
        //
        //  DEBUG
        //
        //----------------------------------------------------- 

        #region DEBUG 
 
        [Conditional("DEBUG")]
        internal void Debug_VerifyBoundsEqual(Rect3D bounds1, Rect3D bounds2, string errorString) 
        {
            // The funny boolean logic below avoids asserts when the cached
            // bounds contain NaNs.  (NaN != NaN)
            bool boundsAreEqual = 
                !(bounds1.X < bounds2.X || bounds1.X > bounds2.X) &&
                !(bounds1.Y < bounds2.Y || bounds1.Y > bounds2.Y) && 
                !(bounds1.Z < bounds2.Z || bounds1.Z > bounds2.Z) && 
                !(bounds1.SizeX < bounds2.SizeX || bounds1.SizeX > bounds2.SizeX) &&
                !(bounds1.SizeY < bounds2.SizeY || bounds1.SizeY > bounds2.SizeY) && 
                !(bounds1.SizeZ < bounds2.SizeZ || bounds1.SizeZ > bounds2.SizeZ);

            Debug.Assert(boundsAreEqual, errorString);
        } 

        [Conditional("DEBUG")] 
        internal void Debug_VerifyCachedSubgraphBounds() 
        {
            Rect3D currentBounds = Rect3D.Empty; 
#if DEBUG
            currentBounds = Debug_CalculateSubgraphBounds();
#endif
            // currentBounds includes Transform so we need to 
            // temporarily transform _bboxSubgraph
            Rect3D cachedBounds = M3DUtil.ComputeTransformedAxisAlignedBoundingBox(ref _bboxSubgraph, Transform); 
 
            Debug_VerifyBoundsEqual(cachedBounds, currentBounds, "Cached bbox subgraph is incorrect!");
        } 

        [Conditional("DEBUG")]
        internal void Debug_VerifyCachedContentBounds()
        { 
            Model3D model = _visual3DModel;
 
            Debug.Assert(model != null); 

            Debug_VerifyBoundsEqual(model.CalculateSubgraphBoundsOuterSpace(), 
                                    _bboxContent, "Cached content bounds is incorrect!");
        }

// [Conditional] does not work on methods that return values 
#if DEBUG
        internal Rect3D Debug_CalculateSubgraphBounds() 
        { 
            Rect3D currentSubgraphBounds = GetContentBounds();
 
            for (int i = 0, count = Visual3DChildrenCount; i < count; i++)
            {
                currentSubgraphBounds.Union(
                    GetVisual3DChild(i).Debug_CalculateSubgraphBounds() 
                    );
            } 
 
            return M3DUtil.ComputeTransformedAxisAlignedBoundingBox(ref currentSubgraphBounds, Transform);
        } 
#endif

        #endregion DEBUG
 
        /// 
        /// Precompute pass. 
        ///  
        internal void PrecomputeRecursive(out Rect3D bboxSubgraph)
        { 
            if (CheckFlagsAnd(VisualFlags.IsSubtreeDirtyForPrecompute))
            {
                //
                // Track which subtrees have nodes that use realization caches. 
                //
 
                bool subTreeUsesRealizationCaches = false; 

                subTreeUsesRealizationCaches |= PrecomputeContent(); 

                //
                // Update the subgraph bounding box which includes the content bounds
                // and the bounds of our children. 
                //
 
                _bboxSubgraph = GetContentBounds(); 

                for (int i = 0, count = Visual3DChildrenCount; i < count; i++) 
                {
                    Visual3D child = GetVisual3DChild(i);

                    Rect3D bboxSubgraphChild; 
                    child.PrecomputeRecursive(out bboxSubgraphChild);
                    _bboxSubgraph.Union(bboxSubgraphChild); 
 
                    subTreeUsesRealizationCaches |=
                        child.CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches); 
                }

                //
                // Update the NodeInSubtreeUsesRealizationCaches bit. 
                //
 
                subTreeUsesRealizationCaches |= CheckFlagsAnd(VisualFlags.NodeUsesRealizationCaches); 
                SetFlags(subTreeUsesRealizationCaches, VisualFlags.NodeInSubtreeUsesRealizationCaches);
                SetFlags(false, VisualFlags.IsSubtreeDirtyForPrecompute); 
            }

            bboxSubgraph = M3DUtil.ComputeTransformedAxisAlignedBoundingBox(ref _bboxSubgraph, Transform);
       } 

        internal void RenderRecursive(RenderContext ctx) 
        { 
            DUCE.Channel channel = ctx.Channel;
            DUCE.ResourceHandle handle = DUCE.ResourceHandle.Null; 
            VisualProxyFlags flags = c_Model3DVisualProxyFlagsDirtyMask;

            //
            // Ensure that the resource for this Visual is sent to our current channel. 
            //
            bool isOnChannel = IsOnChannel(channel); 
            if (isOnChannel) 
            {
                // 
                // Good, we're already on channel. Get the handle and the flags.
                //

                handle = _proxy.GetHandle(channel); 
                flags = _proxy.GetFlags(channel);
            } 
            else 
            {
                // 
                // Create the visual resource on the current channel.
                //
                // Note: we need to update all set properties (the dirty
                //       bit mask is set by default). 
                //
 
                handle = ((DUCE.IResource)this).AddRefOnChannel(channel); 
            }
 
            //
            // Hookup content to the Visual
            //
 
            if ((flags & VisualProxyFlags.IsContentDirty) != 0)
            { 
                RenderContent(ctx, isOnChannel); 
            }
 
            //
            // Update the transform.
            //
 
            if ((flags & VisualProxyFlags.IsTransformDirty) != 0)
            { 
                Transform3D transform = Transform; 
                if (transform != null && InternalIsVisible)
                { 
                    //
                    // Set the new transform resource for this visual.  If transform is
                    // null we don't need to do this.  Also note that the old transform
                    // was disconnected in the Transform property setter. 
                    //
 
                    DUCE.Visual3DNode.SetTransform( 
                        handle,
                        ((DUCE.IResource)transform).AddRefOnChannel(channel), 
                        channel);
                }
                else if (!InternalIsVisible)
                { 
                    DUCE.Visual3DNode.SetTransform(
                        handle, 
                        ((DUCE.IResource)_zeroScale).AddRefOnChannel(channel), 
                        channel);
                } 
                else if (!isOnChannel) /* Transform == null */
                {
                    DUCE.Visual3DNode.SetTransform(
                        handle, 
                        DUCE.ResourceHandle.Null,
                        channel); 
                } 
            }
 
            // Visit children of this node -----------------------------------------------------------------------

            Debug.Assert((flags & VisualProxyFlags.IsContentNodeConnected) == 0,
                "Only HostVisuals are expected to have a content node."); 

            for (int i = 0; i < Visual3DChildrenCount; i++) 
            { 
                Visual3D child = GetVisual3DChild(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(ctx.Channel)) 
                    {
                        if (!child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent))
                        {
                            DUCE.Visual3DNode.InsertChildAt( 
                                handle,
                                ((DUCE.IResource)child).GetHandle(channel), 
                                /* iPosition = */ (uint)i, 
                                ctx.Channel);
 
                            child.SetFlags(channel, true, VisualProxyFlags.IsConnectedToParent);
                        }
                    }
                } 
            }
 
            // 
            // Finally, reset the dirty flags for this visual (at this point,
            // we have handled them all). 
            //

            SetFlags(channel, false, c_Model3DVisualProxyFlagsDirtyMask);
        } 

        ///  
        /// RenderContent is implemented to hook up the Visual3Ds content. 
        /// The implementer of this function can assert that the _hCompNode
        /// is valid on a channel when the function is executed. 
        /// 
        internal void RenderContent(RenderContext ctx, bool isOnChannel)
        {
            DUCE.Channel channel = ctx.Channel; 

            Debug.Assert(!CheckFlagsAnd(channel, VisualProxyFlags.IsContentConnected)); 
            Debug.Assert(IsOnChannel(channel)); 

            // 
            // Create the content on the channel.
            //

            if (_visual3DModel != null) 
            {
                // 
                // Attach the content to the visual resource 
                //
 
                DUCE.Visual3DNode.SetContent(
                    ((DUCE.IResource)this).GetHandle(channel),
                    ((DUCE.IResource)_visual3DModel).AddRefOnChannel(channel),
                    channel); 

                SetFlags(channel, true, VisualProxyFlags.IsContentConnected); 
            } 
            else if (isOnChannel) /* Model == null */
            { 
                DUCE.Visual3DNode.SetContent(
                    ((DUCE.IResource)this).GetHandle(channel),
                    DUCE.ResourceHandle.Null,
                    channel); 
            }
        } 
 
        /// 
        /// Returns true if the specified ancestor is really the ancestor of the 
        /// given descendant.
        /// 
        public bool IsAncestorOf(DependencyObject descendant)
        { 
            Visual visual;
            Visual3D visual3D; 
 
            VisualTreeUtils.AsNonNullVisual(descendant, out visual, out visual3D);
 
            // x86 branch prediction skips the branch on first encounter.  We favor 3D.
            if(visual != null)
            {
                return visual.IsDescendantOf(this); 
            }
 
            return visual3D.IsDescendantOf(this); 
        }
 
        /// 
        /// Returns true if the refernece Visual (this) is a descendant of the argument Visual.
        /// 
        public bool IsDescendantOf(DependencyObject ancestor) 
        {
            if (ancestor == null) 
            { 
                throw new ArgumentNullException("ancestor");
            } 

            VisualTreeUtils.EnsureVisual(ancestor);

            // Walk up the parent chain of the descendant untill we run out 
            // of 3D parents or we find the ancestor.
            Visual3D current = this; 
 
            while (current != null && current != ancestor)
            { 
                // If our 3D parent is null then continue walk in 2D
                if (current._3DParent == null)
                {
                    DependencyObject parent2D = current.InternalVisualParent; 

                    if (parent2D != null) 
                    { 
                        // The type has to be Visual because of the above if condition
                        return ((Visual)parent2D).IsDescendantOf(ancestor); 
                    }
                }

                current = current._3DParent; 
            }
 
            return current == ancestor; 
        }
 
        /// 
        ///     Walks up the Visual tree setting or clearing the given flags.  Unlike
        ///     PropagateFlags this does not terminate when it reaches node with
        ///     the flags already set.  It always walks all the way to the root. 
        /// 
        internal void SetFlagsToRoot(bool value, VisualFlags flag) 
        { 
            Visual3D current = this;
 
            do
            {
                current.SetFlags(value, flag);
 
                if (current._3DParent == null)
                { 
                    VisualTreeUtils.SetFlagsToRoot(InternalVisualParent, value, flag); 
                    return;
                } 

                current = current._3DParent;
            }
            while (current != null); 
        }
 
        ///  
        ///     Finds the first ancestor of the given element which has the given
        ///     flags set. 
        /// 
        internal DependencyObject FindFirstAncestorWithFlagsAnd(VisualFlags flag)
        {
            Visual3D current = this; 

            do 
            { 
                if (current.CheckFlagsAnd(flag))
                { 
                    // The other Visual crossed through this Visual's parent chain. Hence this is our
                    // common ancestor.
                    return current;
                } 

                if (current._3DParent == null) 
                { 
                    return VisualTreeUtils.FindFirstAncestorWithFlagsAnd(InternalVisualParent, flag);
                } 

                current = current._3DParent;
            }
            while (current != null); 

            return null; 
        } 

        ///  
        /// Finds the common ancestor of two Visuals.
        /// 
        /// Returns the common ancestor if the Visuals have one or otherwise null.
        /// If the argument is null. 
        public DependencyObject FindCommonVisualAncestor(DependencyObject otherVisual)
        { 
            VerifyAPIReadOnly(otherVisual); 

            if (otherVisual == null) 
            {
                throw new System.ArgumentNullException("otherVisual");
            }
 
            // Since we can't rely on code running in the CLR, we need to first make sure
            // that the FindCommonAncestor flag is not set. It is enought to ensure this 
            // on one path to the root Visual. 

            // 



 
            SetFlagsToRoot(false, VisualFlags.FindCommonAncestor);
 
            // Walk up the other visual's parent chain and set the FindCommonAncestor flag. 
            VisualTreeUtils.SetFlagsToRoot(otherVisual, true, VisualFlags.FindCommonAncestor);
 
            // Now see if the other Visual's parent chain crosses our parent chain.
            return FindFirstAncestorWithFlagsAnd(VisualFlags.FindCommonAncestor);
        }
 
        /// 
        /// Override this function in derived classes to release unmanaged resources during Dispose 
        /// and during removal of a subtree. 
        /// 
        internal void FreeDUCEResources(DUCE.Channel channel) 
        {
            Transform3D transform = Transform;
            if (!CheckFlagsAnd(channel, VisualProxyFlags.IsTransformDirty))
            { 
                if (InternalIsVisible)
                { 
                    if (transform != null) 
                    {
                        ((DUCE.IResource)transform).ReleaseOnChannel(channel); 
                    }
                }
                else
                { 
                    ((DUCE.IResource)_zeroScale).ReleaseOnChannel(channel);
                } 
            } 

            Model3D model = _visual3DModel; 
            if ((model != null) && (!CheckFlagsAnd(channel, VisualProxyFlags.IsContentDirty)))
            {
                ((DUCE.IResource)model).ReleaseOnChannel(channel);
            } 

            Debug.Assert(IsOnChannel(channel)); 
            Debug.Assert(!CheckFlagsAnd(channel, VisualProxyFlags.IsContentNodeConnected)); 

            _proxy.ReleaseOnChannel(channel); 
        }

        void DUCE.IResource.ReleaseOnChannel(DUCE.Channel channel)
        { 
            ReleaseOnChannelCore(channel);
        } 
 
        internal void ReleaseOnChannelCore(DUCE.Channel channel)
        { 
            if (!IsOnChannel(channel))
            {
                return;
            } 

            // at this point the tree is not connected any more. 
            SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent); 

            FreeDUCEResources(channel); 

            for (int i = 0; i < Visual3DChildrenCount; i++)
            {
                Visual3D child = GetVisual3DChild(i); 
                ((DUCE.IResource)child).ReleaseOnChannel(channel);
            } 
        } 

        ///  
        /// Disconnects a resource attached to this visual.
        /// 
        internal void DisconnectAttachedResource(
            VisualProxyFlags correspondingFlag, 
            DUCE.IResource attachedResource)
        { 
            // 
            // Iterate over the channels this visual is being marshaled to
            // 

            for (int i = 0; i < _proxy.Count; i++)
            {
                VisualProxyFlags flags = _proxy.GetFlags(i); 

                if ((flags & correspondingFlag) == 0) 
                { 
                    DUCE.Channel channel = _proxy.GetChannel(i);
 
                    //
                    // Set the flag so that during render we send
                    // update to the compositor.
                    // 
                    SetFlags(channel, true, correspondingFlag);
 
                    if (correspondingFlag == VisualProxyFlags.IsContentDirty) 
                    {
                        _proxy.SetFlags(i, false, VisualProxyFlags.IsContentConnected); 
                    }

                    //
                    // Add this resource to the queue for delayed-removal. 
                    //
                    channel.AddToRemoveAndReleaseQueue( 
                        null, 
                        attachedResource);
                } 
            }
        }

        internal void UpdateRealizations(RealizationContext rc) 
        {
            Debug.Assert(CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches)); 
 
            Matrix3DStack stack3D = rc.Transform3DStack;
            Transform3D transform = Transform; 

            if (transform != null)
            {
                stack3D.Push(transform.Value); 
            }
 
            Model3D model = _visual3DModel; 
            // It's possible that NodeInSubtreeUsesRealizationCaches is 'true' for
            // one of the children but not the Model so we still check the ProtectedContent 
            if (model != null && model._flags[Model3D.RequiresRealizationFlag])
            {
                model.MarkVisibleRealizations(rc);
            } 

 
            // should this know about children? 
            for (int i = 0; i < Visual3DChildrenCount; i++)
            { 
                Visual3D child = GetVisual3DChild(i);
                if (child.CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches))
                {
                    child.UpdateRealizations(rc); 
                }
            } 
 
            if (transform != null)
            { 
                stack3D.Pop();
            }
        }
 
        // Normally the inheritence context is the same as our parent.  When it differs,
        // we store the value in the _inheritanceContext UncommonField.  See comments 
        // on the _inheritanceContext and UseParentAsContext members for more info. 
        internal override DependencyObject InheritanceContext
        { 
            get
            {
                DependencyObject value = _inheritanceContext.GetValue(this);
 
                if (value == UseParentAsContext)
                { 
                    return InternalVisualParent; 
                }
 
                return value;
            }
        }
 
        internal override void AddInheritanceContext(DependencyObject context, DependencyProperty property)
        { 
            base.AddInheritanceContext(context, property); 

            // Call local helper 
            AddOrRemoveInheritanceContext(context);
        }

        internal override void RemoveInheritanceContext(DependencyObject context, DependencyProperty property) 
        {
            base.RemoveInheritanceContext(context, property); 
 
            // Call local helper
            AddOrRemoveInheritanceContext(null); 
        }

        // Local helping for adding or removing an inheritance context
        private void AddOrRemoveInheritanceContext(DependencyObject newInheritanceContext) 
        {
            // If we are using our parent as our inheritance context the InheritanceContext 
            // property will already be returning the new context, but we still need to treat 
            // this as a change so we notify our dependants.
            bool contextChanged = 
                InheritanceContext != newInheritanceContext ||
                (_inheritanceContext.GetValue(this) == UseParentAsContext &&
                    newInheritanceContext == InternalVisualParent);
 
            if (contextChanged)
            { 
                // Pick up the new context 
                SetInheritanceContext(newInheritanceContext);
                OnInheritanceContextChanged(EventArgs.Empty); 
            }
        }

        internal override bool HasMultipleInheritanceContexts 
        {
            get { return base.HasMultipleInheritanceContexts; } 
        } 

        internal override void OnInheritanceContextChangedCore(EventArgs args) // ancestor changed 
        {
            base.OnInheritanceContextChangedCore(args);

            for (int i = 0; i < Visual3DChildrenCount; i++) 
            {
                DependencyObject child = GetVisual3DChild(i); 
 
                Debug.Assert(child.InheritanceContext == this,
                    "How did a child get inserted without propagating our inheritance context?"); 

                child.OnInheritanceContextChanged(args);
            }
        } 

        #endregion Internal Methods 
 
        // -------------------------------------------------------------------
        // 
        //   Visual-to-Visual Transforms
        //
        // --------------------------------------------------------------------
 
        #region Visual-to-Visual Transforms
 
        ///  
        /// Returns a transform that can be used to transform coordinates from this
        /// node to the specified ancestor, or null if the transformation cannot be created. 
        /// 2D is allowed to be between the 3D nodes.
        /// 
        /// 
        /// If ancestor is null. 
        /// 
        ///  
        /// If the ancestor Visual3D is not a ancestor of Visual3D. 
        /// 
        /// If the Visual3Ds are not connected. 
        public GeneralTransform3D TransformToAncestor(Visual3D ancestor)
        {
            if (ancestor == null)
            { 
                throw new ArgumentNullException("ancestor");
            } 
 
            VerifyAPIReadOnly(ancestor);
 
            return InternalTransformToAncestor(ancestor, false);
        }

 
        /// 
        /// Returns a transform that can be used to transform coordinates from this 
        /// node to the specified descendant, or null if the transform from descendant to "this" 
        /// is non-invertible.  This is the case when 2D is between the nodes.
        /// 
        /// 
        /// 
        /// If the reference Visual3D is not a ancestor of the descendant Visual3D.
        ///  
        /// If the descendant argument is null.
        /// If the Visual3Ds are not connected. 
        public GeneralTransform3D TransformToDescendant(Visual3D descendant) 
        {
            if (descendant == null) 
            {
                throw new ArgumentNullException("descendant");
            }
 
            VerifyAPIReadOnly(descendant);
 
            return descendant.InternalTransformToAncestor(this, true); 
        }
 
        /// 
        /// Returns the transform or the inverse transform between this visual and the specified ancestor.
        /// If inverse is requested but does not exist (if the transform is not invertible), null is returned.
        ///  
        /// Ancestor visual.
        /// Returns inverse if this argument is true. 
        private GeneralTransform3D InternalTransformToAncestor(Visual3D ancestor, bool inverse) 
        {
            Debug.Assert(ancestor != null); 

            // used to track if all the collected transforms on the way to the ancestor were valid
            bool success = true;
 
            DependencyObject g = this;
            Visual3D lastVisual3D = null; 
 
            Matrix3D m = Matrix3D.Identity;
            GeneralTransform3DGroup group = null; 

            // This while loop will walk up the visual tree until we encounter the ancestor.
            // As it does so, it will accumulate the descendent->ancestor transform.
            // In most cases, this is simply a matrix, though if we encounter a 2D node we need to 
            // transform from 3D out in to 2D and then back in to 3D and continue the parent walk.
            // We will accumulate the current transform in a matrix until we encounter a 2D parent, 
            // at which point we will add the matrix's current value and the transform from 3D to 2D to 3D 
            // to the GeneralTransform3DGroup and continue to accumulate further transforms in the matrix again.
            // At the end of this loop, we will have 0 or more transforms in the GeneralTransform3DGroup 
            // and the matrix which, if not identity, should be appended to the GeneralTransform3DGroup.
            // If, as is commonly the case, this loop terminates without encountering a 2D parent
            // we will simply use the Matrix3D.
 
            while ((VisualTreeHelper.GetParent(g) != null) && (g != ancestor))
            { 
                Visual3D gAsVisual3D = g as Visual3D; 
                if (gAsVisual3D != null)
                { 
                    Transform3D transform = gAsVisual3D.Transform;
                    if (transform != null)
                    {
                        transform.Append(ref m); 
                    }
 
                    lastVisual3D = gAsVisual3D; 
                    g = VisualTreeHelper.GetParent(gAsVisual3D);
                } 
                else
                {
                    if (group == null)
                    { 
                        group = new GeneralTransform3DGroup();
                    } 
 
                    group.Children.Add(new MatrixTransform3D(m));
                    m = Matrix3D.Identity; 

                    // construct the 3D to 2D to 3D transform
                    Visual gAsVisual = g as Visual;
                    GeneralTransform3DTo2D transform3DTo2D = lastVisual3D.TransformToAncestor(gAsVisual); 

                    // now find the 3D parent of the 2D object 
                    Visual3D containing3DParent = VisualTreeHelper.GetContainingVisual3D(gAsVisual); 

                    // if containing3DParent is null, then the ancestor parameter is not really an ancestor 
                    // break out of the loop to allow it to fail
                    if (containing3DParent == null)
                    {
                        break; 
                    }
 
                    GeneralTransform2DTo3D transform2DTo3D = gAsVisual.TransformToAncestor(containing3DParent); 

                    // if either transform ends up being null then we don't have a transform 
                    if (transform3DTo2D == null || transform2DTo3D == null)
                    {
                        // we don't want to break here because although we own't be able to create a valid transformation
                        // we also want to throw an exception if the ancestor passed in is not a valid ancestor.  We then 
                        // continue the tree walk to make sure.
                        success = false; 
                    } 
                    else
                    { 
                        group.Children.Add(new GeneralTransform3DTo2DTo3D(transform3DTo2D, transform2DTo3D));
                    }

                    // the last visual3D found is where we continue the search 
                    g = containing3DParent;
                } 
            } 

            if (g != ancestor) 
            {
                throw new System.InvalidOperationException(SR.Get(inverse ? SRID.Visual_NotADescendant : SRID.Visual_NotAnAncestor));
            }
 
            // construct the generaltransform3d to return and invert it if necessary
            GeneralTransform3D finalTransform = null; 
 
            // if we successfully found a transform then we can create it here, otherwise finalTransform stays null
            if (success) 
            {
                if (group != null)
                {
                    finalTransform = group; 
                }
                else 
                { 
                    finalTransform = new MatrixTransform3D(m);
                } 

                if (inverse)
                {
                    finalTransform = finalTransform.Inverse; 
                }
            } 
 
            if (finalTransform != null)
            { 
                finalTransform.Freeze();
            }

            return finalTransform; 
        }
 
        ///  
        /// Returns a transform that can be used to transform coordinate from this
        /// node to the specified ancestor, or null if the transform does not exist. 
        /// This transform will take a 3D point, and then project it in to 2D space.
        /// The resulting point is the transformed 3D point in the coordinate space
        /// of the given ancestor.
        /// 
        /// 
        ///  
        /// If ancestor is null. 
        /// 
        ///  
        /// If the ancestor Visual is not an ancestor of this.
        /// 
        /// If the Visual3D and Visual are not connected.
        public GeneralTransform3DTo2D TransformToAncestor(Visual ancestor) 
        {
            if (ancestor == null) 
            { 
                throw new ArgumentNullException("ancestor");
            } 

            VerifyAPIReadOnly(ancestor);

            return InternalTransformToAncestor(ancestor); 
        }
 
        ///  
        /// Provides the transform between this visual3D and the specified ancestor, or null
        /// if the transform does not exist. 
        ///
        /// 
        /// Ancestor visual.
        /// The transform from 3D to 2D 
        internal GeneralTransform3DTo2D InternalTransformToAncestor(Visual ancestor)
        { 
            Debug.Assert(ancestor != null); 

            // get the transform out of 3D and in to 2D 
            Viewport3DVisual containingViewport;
            Matrix3D projectionTransform;

            if (!M3DUtil.TryTransformToViewport3DVisual(this, out containingViewport, out projectionTransform)) 
            {
                return null; 
            } 

            // get the transform from the Viewport3DVisual to the ancestor 
            GeneralTransform transformIn2D = containingViewport.TransformToAncestor(ancestor);

            // package the two up in the transformTo2D
            GeneralTransform3DTo2D result = new GeneralTransform3DTo2D(projectionTransform, transformIn2D); 
            result.Freeze();
 
            return result; 
        }
 
        #endregion Visual-to-Visual Transforms

        //-----------------------------------------------------
        // 
        //  Internal Properties
        // 
        //------------------------------------------------------ 

        #region Internal Properties 

        internal DependencyObject InternalVisualParent
        {
            get 
            {
                if (_3DParent != null) 
                { 
                    Debug.Assert(_2DParent.GetValue(this) == null,
                        "Only one parent pointer should be set at a time."); 

                    return _3DParent;
                }
 
                DependencyObject parent2D = _2DParent.GetValue(this);
 
                Debug.Assert(parent2D == null || parent2D is Viewport3DVisual, 
                    "The only acceptable 2D parent for a Visual3D is a Viewport3DVisual.");
 
                return parent2D;
            }
        }
 
        internal int ParentIndex
        { 
            get { return _parentIndex; } 
            set { _parentIndex = value; }
        } 

        // Are we in the process of iterating the visual children.
        // This flag is set during a descendents walk, for property invalidation.
        internal bool IsVisualChildrenIterationInProgress 
        {
            [FriendAccessAllowed] 
            get { return CheckFlagsAnd(VisualFlags.IsVisualChildrenIterationInProgress); } 

            [FriendAccessAllowed] 
            set { SetFlags(value, VisualFlags.IsVisualChildrenIterationInProgress); }
        }

        #endregion Internal Properties 

        // -------------------------------------------------------------------- 
        // 
        //   Visual flags manipulation
        // 
        // -------------------------------------------------------------------

        #region Visual flags manipulation
 
        /// 
        /// SetFlagsOnAllChannels is used to set or unset one 
        /// or multiple flags on all channels this visual is 
        /// marshaled to.
        ///  
        internal void SetFlagsOnAllChannels(
            bool value,
            VisualProxyFlags flagsToChange)
        { 
            _proxy.SetFlagsOnAllChannels(
                value, 
                flagsToChange); 
        }
 
        /// 
        /// SetFlags is used to set or unset one or multiple flags on a given channel.
        /// 
        internal void SetFlags( 
            DUCE.Channel channel,
            bool value, 
            VisualProxyFlags flagsToChange) 
        {
            _proxy.SetFlags( 
                channel,
                value,
                flagsToChange);
        } 

        ///  
        /// SetFlags is used to set or unset one or multiple node flags on the node. 
        /// 
        internal void SetFlags(bool value, VisualFlags Flags) 
        {
            _flags = value ? (_flags | Flags) : (_flags & (~Flags));
        }
 
        /// 
        /// CheckFlagsOnAllChannels returns true if all flags in 
        /// the bitmask flags are set on all channels this visual is 
        /// marshaled to.
        ///  
        /// 
        /// If there aren't any bits set on the specified flags
        /// the method returns true.
        ///  
        internal bool CheckFlagsOnAllChannels(VisualProxyFlags flagsToCheck)
        { 
            return _proxy.CheckFlagsOnAllChannels(flagsToCheck); 
        }
 
        /// 
        /// CheckFlagsAnd returns true if all flags in the bitmask flags
        /// are set on a given channel.
        ///  
        /// 
        /// If there aren't any bits set on the specified flags 
        /// the method returns true. 
        /// 
        internal bool CheckFlagsAnd( 
            DUCE.Channel channel,
            VisualProxyFlags flagsToCheck)
        {
            return (_proxy.GetFlags(channel) & flagsToCheck) == flagsToCheck; 
        }
 
        ///  
        /// CheckFlagsAnd returns true if all flags in the bitmask flags are set on the node.
        ///  
        /// If there aren't any bits set on the specified flags the method
        /// returns true
        internal bool CheckFlagsAnd(VisualFlags flags)
        { 
            return (_flags & flags) == flags;
        } 
 
        /// 
        /// Returns the child at index "index" (in most cases this will be 
        /// a Visual, but it some cases, Viewport3DVisual for instance,
        /// this is a Visual3D).
        ///
        /// Used only by VisualTreeHelper. 
        /// 
        internal virtual DependencyObject InternalGet2DOr3DVisualChild(int index) 
        { 
            // Call the right virtual method.
            return GetVisual3DChild(index); 
        }

        /// 
        /// Returns the number of children of this object (in most cases this will be 
        /// the number of Visuals, but it some cases, Viewport3DVisual for instance,
        /// this is the number of Visual3Ds). 
        /// 
        /// Used only by VisualTreeHelper.
        ///  
        internal virtual int InternalVisual2DOr3DChildrenCount
        {
            get
            { 
                // Call the right virtual method.
                return Visual3DChildrenCount; 
            } 
        }
 
        /// 
        /// Checks if any of the specified flags is set on a given channel.
        /// 
        ///  
        /// If there aren't any bits set on the specified flags
        /// the method returns true. 
        ///  
        internal bool CheckFlagsOr(
            DUCE.Channel channel, 
            VisualProxyFlags flagsToCheck)
        {
            return (_proxy.GetFlags(channel) & flagsToCheck) != VisualProxyFlags.None;
        } 

        ///  
        /// Checks if any of the specified flags is set on the node. 
        /// 
        /// If there aren't any bits set on the specified flags the method 
        /// returns true
        internal bool CheckFlagsOr(VisualFlags flags)
        {
            return (flags == 0) || ((_flags & flags) > 0); 
        }
 
        ///  
        ///     Check all the children for a bit.
        ///  
        internal static bool DoAnyChildrenHaveABitSet(Visual3D pe,
                                                      VisualFlags flag)
        {
 
            int count = pe.InternalVisual2DOr3DChildrenCount;
            for (int i = 0; i < count; i++) 
            { 
                DependencyObject child = pe.InternalGet2DOr3DVisualChild(i);
 
                Visual v = null;
                Visual3D v3D = null;
                VisualTreeUtils.AsNonNullVisual(child, out v, out v3D);
 
                if (v != null && v.CheckFlagsAnd(flag))
                { 
                    return true; 
                }
                else if (v3D != null && v3D.CheckFlagsAnd(flag)) 
                {
                    return true;
                }
            } 

            return false; 
        } 

        ///  
        /// Propagates the flags up to the root.
        /// 
        /// 
        /// The walk stops on a node with all of the required flags set. 
        /// 
        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.NodeIsVisualBrushRoot), 
                    "Visual3Ds should never be the root of a VisualBrush.");

                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;
            } 
        }
 
        #endregion Visual flags manipulation 

        //------------------------------------------------------ 
        //
        //  Private Methods
        //
        //----------------------------------------------------- 

        #region Private Methods 
 
        private void SetInheritanceContext(DependencyObject newInheritanceContext)
        { 
            if (newInheritanceContext == InternalVisualParent)
            {
                _inheritanceContext.ClearValue(this);
 
                Debug.Assert(_inheritanceContext.GetValue(this) == UseParentAsContext,
                    "Clearing the _inheritanceContext uncommon field should put us in the UseParentAsContext state."); 
            } 
            else
            { 
                _inheritanceContext.SetValue(this, newInheritanceContext);
            }
        }
 
        #endregion Private Methods
 
        //----------------------------------------------------- 
        //
        //  Internal Fields 
        //
        //-----------------------------------------------------

        #region Internal Fields 

        internal VisualProxy _proxy; 
 
        #endregion Internal Fields
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
 
        #region Private Fields 

        // If the parent of the Visual3D is another Visual3D we store the parent in the _3DParent field. 
        // If the parent is a 2D node (as is the case when this is the root of a Viewport3DVisual) we
        // store the parent in an UncommonField.  Both fields must be considered when determining
        // the parent of this node.
        private static readonly UncommonField _2DParent = 
            new UncommonField(/* defaultValue = */ null);
 
        // Sentinel value we use to differentiate between a null inheritance context stored in the 
        // _inheritanceContext uncommon field and "empty", meaning use the parent as context.
        private static readonly DependencyObject UseParentAsContext = new DependencyObject(); 

        // Normally the inheritance context is the same as the parent, except when we are parent to
        // a Viewport3D visual, in which case we use this uncommon field to store are alternate context.
        private static readonly UncommonField _inheritanceContext = 
            new UncommonField(/* defaultValue = */ UseParentAsContext);
 
        private static readonly UncommonField AncestorChangedEventField 
            = new UncommonField();
 
        private Visual3D _3DParent;
        private int _parentIndex = -1;

        private VisualFlags _flags; 

        // Untransformed *cached* content bounds. Do not access it directly -- instead 
        // use GetContentBounds() 
        private Rect3D _bboxContent;
 
        // Untransformed *cached* subgraph bounds. Do not access it directly -- instead
        // use the BBoxSubgraph property.
        private Rect3D _bboxSubgraph = Rect3D.Empty;
 
        private bool _internalIsVisible;
 
        private static readonly ScaleTransform3D _zeroScale = new ScaleTransform3D(0, 0, 0); 

        private Model3D _visual3DModel; 

        #endregion Private Fields

        //------------------------------------------------------ 
        //
        //  Protected Fields 
        // 
        //------------------------------------------------------
 
        #region Protected Fields

        #endregion Protected Fields
 
    }
} 
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (c) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
// 
// History:
//  6/8/2005 : [....] - Created 
//
//---------------------------------------------------------------------------

using MS.Internal; 
using MS.Internal.Media;
using MS.Internal.Media3D; 
using MS.Internal.PresentationCore; 
using System;
using System.Diagnostics; 
using System.Security;
using System.Windows.Media.Composition;
using System.Windows.Media;
 
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 
 
namespace System.Windows.Media.Media3D
{ 
    /// 
    ///     Visual3D is the base class for all 3D visual elements.
    /// 
    public abstract partial class Visual3D : DependencyObject, DUCE.IResource, IVisual3DContainer 
    {
        // ------------------------------------------------------------------- 
        // 
        //   Constants
        // 
        // -------------------------------------------------------------------

        #region Constants
 
        /// 
        /// This is the dirty mask for a visual, set every time we marshall 
        /// a visual to a channel and reset by the end of the render pass. 
        /// 
        private const VisualProxyFlags c_Model3DVisualProxyFlagsDirtyMask = 
              VisualProxyFlags.IsSubtreeDirtyForRender
            | VisualProxyFlags.IsContentDirty
            | VisualProxyFlags.IsTransformDirty;
 
        #endregion Constants
 
        //------------------------------------------------------ 
        //
        //  Constructors 
        //
        //-----------------------------------------------------

        #region Constructors 

        // Prevent 3rd parties from extending this abstract base class. 
        internal Visual3D() 
        {
            _internalIsVisible = true; 
        }

        #endregion Constructors
 

        // -------------------------------------------------------------------- 
        // 
        //   IResource implementation
        // 
        // --------------------------------------------------------------------

        #region IResource implementation
 
        /// 
        /// This is used to check if the composition node 
        /// for the visual is on channel 
        /// 
        ///  
        /// 
        internal bool IsOnChannel(DUCE.Channel channel)
        {
            return _proxy.IsOnChannel(channel); 
        }
 
        ///  
        /// Returns the handle this visual has on the given channel.
        ///  
        /// 
        /// 
        DUCE.ResourceHandle DUCE.IResource.GetHandle(DUCE.Channel channel)
        { 
            return _proxy.GetHandle(channel);
        } 
 
        /// 
        /// Returns the handle this visual has on the given channel. 
        /// Note: The 3D handle is the normal handle for Visual3D
        /// 
        DUCE.ResourceHandle DUCE.IResource.Get3DHandle(DUCE.Channel channel)
        { 
            return _proxy.GetHandle(channel);
        } 
 
        /// 
        /// This is used to create or addref the visual resource 
        /// on the given channel
        /// 
        /// 
        ///  
        DUCE.ResourceHandle DUCE.IResource.AddRefOnChannel(DUCE.Channel channel)
        { 
            _proxy.CreateOrAddRefOnChannel(channel, DUCE.ResourceType.TYPE_VISUAL3D); 

            return _proxy.GetHandle(channel); 
        }

        /// 
        /// Sends a command to compositor to remove the child 
        /// from its parent on the channel.
        ///  
        void DUCE.IResource.RemoveChildFromParent( 
                DUCE.IResource parent,
                DUCE.Channel channel) 
        {
            DUCE.Visual3DNode.RemoveChild(
                parent.Get3DHandle(channel),
                _proxy.GetHandle(channel), 
                channel);
        } 
 
        int DUCE.IResource.GetChannelCount()
        { 
            return _proxy.Count;
        }

        DUCE.Channel DUCE.IResource.GetChannel(int index) 
        {
            return _proxy.GetChannel(index); 
        } 

        #endregion IResource implementation 


        //-----------------------------------------------------
        // 
        //  Public Methods
        // 
        //------------------------------------------------------ 

        #region Public Methods 

        /// 
        ///    DependencyProperty which backs the ModelVisual3D.Transform property.
        ///  
        public static readonly DependencyProperty TransformProperty =
            DependencyProperty.Register( 
                    "Transform", 
                    /* propertyType = */ typeof(Transform3D),
                    /* ownerType = */ typeof(Visual3D), 
                    new PropertyMetadata(Transform3D.Identity, TransformPropertyChanged),
                    (ValidateValueCallback) delegate { return MediaContext.CurrentMediaContext.WriteAccessEnabled; });

        private static void TransformPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Visual3D owner = ((Visual3D) d); 
 
            if (!e.IsASubPropertyChange)
            { 
                if (e.OldValue != null)
                {
                    owner.DisconnectAttachedResource(
                        VisualProxyFlags.IsTransformDirty, 
                        ((DUCE.IResource) e.OldValue));
                } 
 
                owner.SetFlagsOnAllChannels(true, VisualProxyFlags.IsTransformDirty);
            } 

            // NTRAID#Longhorn-1614112-2006/05/25-[....] - Stop over-invalidating _bboxSubgraph
            //
            // We currently maintain a cache of both a ModelVisual3D’s content 
            // and subgraph bounds.  A better solution that would be both a 2D
            // and 3D win would be to stop invalidating _bboxSubgraph when a 
            // visual’s transform changes. 
            owner.RenderChanged(/* sender = */ owner, EventArgs.Empty);
        } 

        /// 
        ///     Transform for this Visual3D.
        ///  
        public Transform3D Transform
        { 
            get 
            {
                return (Transform3D) GetValue(TransformProperty); 
            }

            set
            { 
                SetValue(TransformProperty, value);
            } 
        } 

        #endregion Public Methods 

        //-----------------------------------------------------
        //
        //  Public Properties 
        //
        //----------------------------------------------------- 
 
        //-----------------------------------------------------
        // 
        //  Public Events
        //
        //------------------------------------------------------
 
        //-----------------------------------------------------
        // 
        //  Protected Methods 
        //
        //------------------------------------------------------ 

        #region Protected Methods

        ///  
        /// AttachChild
        /// 
        ///    Derived classes must call this method to notify the Visual3D layer that a new 
        ///    child appeard in the children collection. The Visual3D layer will then call the GetVisual3DChild
        ///    method to find out where the child was added. 
        ///
        ///  Remark: To move a Visual3D child in a collection it must be first disconnected and then connected
        ///    again. (Moving forward we might want to add a special optimization there so that we do not
        ///    unmarshal our composition resources). 
        /// 
        protected void AddVisual3DChild(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 == null); 

            child.SetParent(this); 

            // set the inheritance context so databinding, etc... work
            ProvideSelfAsInheritanceContext(child, null);
 
            // The child already might be dirty. Hence we need to propagate dirty information
            // from the parent and from the child. 
            Visual3D.PropagateFlags( 
                this,
                VisualFlags.IsSubtreeDirtyForPrecompute, 
                VisualProxyFlags.IsSubtreeDirtyForRender);

            Visual3D.PropagateFlags(
                child, 
                VisualFlags.IsSubtreeDirtyForPrecompute,
                VisualProxyFlags.IsSubtreeDirtyForRender); 
 
            //
 

            // Fire notifications
            OnVisualChildrenChanged(child, /* visualRemoved = */ null);
 
            child.FireOnVisualParentChanged(null);
        } 
 

        ///  
        /// 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.
        /// 
        ///  
        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)) 
                {
                    channel.AddToRemoveAndReleaseQueue( 
                        this,
                        child);

                    child.SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent); 
                }
            } 
 
            //
            // 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);
        } 
 
        /// 
        ///    The InternalIsVisible property roughly corresponds to the Opacity in the Visual world. 
        ///    When it is set to true, then the actual transform used for this visual on the MIL side
        ///    is set to a zero scale transform.  This makes the object invisible.
        /// 
        internal bool InternalIsVisible 
        {
            get 
            { 
                return _internalIsVisible;
            } 
            set
            {
                if (_internalIsVisible != value)
                { 
                    // if we're going from Not Visible -> Visibile remove the zero scale from the Channel
                    // otherwise remove the user's transform 
                    if (value) 
                    {
                        DisconnectAttachedResource( 
                            VisualProxyFlags.IsTransformDirty,
                            ((DUCE.IResource)_zeroScale));
                    }
                    else 
                    {
                        Transform3D transform = Transform; 
 
                        if (transform != null)
                        { 
                            DisconnectAttachedResource(
                                VisualProxyFlags.IsTransformDirty,
                                ((DUCE.IResource)transform));
                        } 
                    }
 
                    SetFlagsOnAllChannels(true, VisualProxyFlags.IsTransformDirty); 

                    RenderChanged(/* sender = */ this, EventArgs.Empty); 

                    _internalIsVisible = value;
                }
            } 
        }
 
        // isSubpropertyChange indicates whether a subproperty on Visual3DModel changed. 
        // In this case oldValue is ignored, since the value hasn't changed.  If it isn't a
        // sub property change, then oldValue gives the previous value of the Visual3DModel property. 
        private void Visual3DModelPropertyChanged(Model3D oldValue, bool isSubpropertyChange)
        {
            if (!isSubpropertyChange)
            { 
                if (oldValue != null)
                { 
                    DisconnectAttachedResource(VisualProxyFlags.IsContentDirty, 
                                               oldValue);
                } 

                SetFlagsOnAllChannels(true, VisualProxyFlags.IsContentDirty);
            }
 
            SetFlags(false, VisualFlags.Are3DContentBoundsValid);
 
            RenderChanged(/* sender = */ this, EventArgs.Empty); 
        }
 
        private void Visual3DModelPropertyChanged(object o, EventArgs e)
        {
            // forward on to the main property changed method.  Since this method is
            // only called on subproperty chanes, oldValue is meaningless. 
            Visual3DModelPropertyChanged(null, /* isSubpropertyChange = */ true);
        } 
 
        /// 
        ///     The Model3D to render 
        /// 
        protected Model3D Visual3DModel
        {
            get 
            {
                VerifyAPIReadOnly(); 
 
                return _visual3DModel;
            } 

            set
            {
                VerifyAPIReadWrite(); 

                if (value != _visual3DModel) 
                { 
                    // remove the old change listener
                    if (_visual3DModel != null && !_visual3DModel.IsFrozenInternal) 
                    {
                        _visual3DModel.ChangedInternal -= Visual3DModelPropertyChanged;
                    }
 
                    // notify of the property change
                    Visual3DModelPropertyChanged(_visual3DModel, /* isSubpropertyChange = */ false); 
                    _visual3DModel = value; 

                    // set the new one 
                    if (_visual3DModel != null && !_visual3DModel.IsFrozenInternal)
                    {
                        _visual3DModel.ChangedInternal += Visual3DModelPropertyChanged;
                    } 
                }
            } 
        } 

        ///  
        /// This is called when the parent link of the Visual is changed.
        /// This method executes important base functionality before calling the
        /// overridable virtual.
        ///  
        /// Old parent or null if the Visual did not have a parent before.
        internal virtual void FireOnVisualParentChanged(DependencyObject oldParent) 
        { 
            // Call the ParentChanged virtual before firing the Ancestor Changed Event
            OnVisualParentChanged(oldParent); 

            // If we are attaching to a tree then
            // send the bit up if we need to.
            if (oldParent == null) 
            {
                Debug.Assert(VisualTreeHelper.GetParent(this) != null, "If oldParent is null, current parent should != null."); 
 
                if(CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                { 
                    Visual.SetTreeBits(
                        VisualTreeHelper.GetParent(this),
                        VisualFlags.SubTreeHoldsAncestorChanged,
                        VisualFlags.RegisteredForAncestorChanged); 
                }
            } 
            // If we are cutting a sub tree off then 
            // clear the bit in the main tree above if we need to.
            else 
            {
                if (CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                {
                    Visual.ClearTreeBits( 
                        oldParent,
                        VisualFlags.SubTreeHoldsAncestorChanged, 
                        VisualFlags.RegisteredForAncestorChanged); 
                }
            } 

            // Fire the Ancestor changed Event on the nodes.
            AncestorChangedEventArgs args = new AncestorChangedEventArgs(this, oldParent);
            ProcessAncestorChangedNotificationRecursive(this, args); 
        }
 
        ///  
        ///   Add removed delegates to the VisualAncenstorChanged Event.
        ///  
        /// 
        ///     This also sets/clears the tree-searching bit up the tree
        /// 
        internal event Visual.AncestorChangedEventHandler VisualAncestorChanged 
        {
            add 
            { 
                Visual.AncestorChangedEventHandler newHandler = AncestorChangedEventField.GetValue(this);
 
                if (newHandler == null)
                {
                    newHandler = value;
                } 
                else
                { 
                    newHandler += value; 
                }
 
                AncestorChangedEventField.SetValue(this, newHandler);

                Visual.SetTreeBits(
                    this, 
                    VisualFlags.SubTreeHoldsAncestorChanged,
                    VisualFlags.RegisteredForAncestorChanged); 
            } 

            remove 
            {
                // check that we are Disabling a node that was previously Enabled
                if(CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                { 
                    Visual.ClearTreeBits(
                                        this, 
                                        VisualFlags.SubTreeHoldsAncestorChanged, 
                                        VisualFlags.RegisteredForAncestorChanged);
                } 

                // if we are Disabling a Visual that was not Enabled then this
                // search should fail.  But it is safe to check.
                Visual.AncestorChangedEventHandler newHandler = AncestorChangedEventField.GetValue(this); 

                if (newHandler != null) 
                { 
                    newHandler -= value;
 
                    if(newHandler == null)
                    {
                        AncestorChangedEventField.ClearValue(this);
                    } 
                    else
                    { 
                        AncestorChangedEventField.SetValue(this, newHandler); 
                    }
                } 
            }
        }

        ///  
        ///     Walks down in the tree for nodes that have AncestorChanged Handlers
        ///     registered and calls them. 
        ///     It uses Flag bits that help it prune the walk.  This should go 
        ///     straight to the relevent nodes.
        ///  
        internal static void ProcessAncestorChangedNotificationRecursive(DependencyObject e, AncestorChangedEventArgs args)
        {
            if (e is Visual)
            { 
                Visual.ProcessAncestorChangedNotificationRecursive(e, args);
            } 
            else 
            {
                Visual3D eAsVisual3D = e as Visual3D; 

                // If the flag is not set, then we are Done.
                if(!eAsVisual3D.CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                { 
                    return;
                } 
 
                // If there is a handler on this node, then fire it.
                Visual.AncestorChangedEventHandler handler = AncestorChangedEventField.GetValue(eAsVisual3D); 

                if(handler != null)
                {
                    handler(eAsVisual3D, args); 
                }
 
                // Decend into the children. 
                int count = eAsVisual3D.InternalVisual2DOr3DChildrenCount;
                for (int i = 0; i < count; i++) 
                {
                    DependencyObject child = eAsVisual3D.InternalGet2DOr3DVisualChild(i);
                    if (child != null)
                    { 
                        Visual3D.ProcessAncestorChangedNotificationRecursive(child, args);
                    } 
                } 
            }
        } 


        /// 
        /// OnVisualParentChanged is called when the parent of the Visual is changed. 
        /// 
        /// Old parent or null if the Visual did not have a parent before. 
        protected internal virtual void OnVisualParentChanged(DependencyObject oldParent) 
        {
        } 

        /// 
        /// OnVisualChildrenChanged is called when the VisualCollection of the Visual is edited.
        ///  
        protected internal virtual void OnVisualChildrenChanged(
            DependencyObject visualAdded, 
            DependencyObject visualRemoved) 
        {
        } 

        #endregion Protected Methods

        //------------------------------------------------------ 
        //
        //  Internal Methods 
        // 
        //-----------------------------------------------------
 
        #region Internal Methods

        internal bool DoesRayHitSubgraphBounds(RayHitTestParameters rayParams)
        { 
            Point3D origin;
            Vector3D direction; 
            rayParams.GetLocalLine(out origin, out direction); 

            Rect3D bboxSubgraph = VisualDescendantBounds; 
            return LineUtil.ComputeLineBoxIntersection(ref origin, ref direction, ref bboxSubgraph, rayParams.IsRay);
        }

        ///  
        /// Initiate a hit test using delegates.
        ///  
        internal void HitTest( 
            HitTestFilterCallback filterCallback,
            HitTestResultCallback resultCallback, 
            HitTestParameters3D hitTestParameters)
        {
            if (resultCallback == null)
            { 
                throw new ArgumentNullException("resultCallback");
            } 
 
            if (hitTestParameters == null)
            { 
                throw new ArgumentNullException("hitTestParameters");
            }

            VerifyAPIReadWrite(); 

            RayHitTestParameters rayParams = hitTestParameters as RayHitTestParameters; 
 
            if (rayParams != null)
            { 
                // In case the user is reusing the same RayHitTestParameters
                rayParams.ClearResults();

                HitTestResultBehavior result = RayHitTest(filterCallback, rayParams); 

                rayParams.RaiseCallback(resultCallback, filterCallback, result); 
            } 
            else
            { 
                // This should never happen, users can not extend the abstract HitTestParameters3D class.
                Invariant.Assert(false,
                    String.Format(System.Globalization.CultureInfo.InvariantCulture,
                        "'{0}' HitTestParameters3D are not supported on {1}.", 
                        hitTestParameters.GetType().Name, this.GetType().Name));
            } 
        } 

        internal HitTestResultBehavior RayHitTest( 
            HitTestFilterCallback filterCallback,
            RayHitTestParameters rayParams)
        {
            if (DoesRayHitSubgraphBounds(rayParams)) 
            {
                // 
                // Determine if there is a special filter behavior defined for this 
                // Visual.
                // 

                HitTestFilterBehavior behavior = HitTestFilterBehavior.Continue;

                if (filterCallback != null) 
                {
                    behavior = filterCallback(this); 
 
                    if (HTFBInterpreter.SkipSubgraph(behavior)) return HitTestResultBehavior.Continue;
                    if (HTFBInterpreter.Stop(behavior)) return HitTestResultBehavior.Stop; 
                }

                //
                // Hit test against the children. 
                //
 
                if (HTFBInterpreter.IncludeChildren(behavior)) 
                {
                    HitTestResultBehavior result = HitTestChildren(filterCallback, rayParams); 

                    if (result == HitTestResultBehavior.Stop) return HitTestResultBehavior.Stop;
                }
 
                //
                // Hit test against the content of this Visual. 
                // 

                if (HTFBInterpreter.DoHitTest(behavior)) 
                {
                    RayHitTestInternal(filterCallback, rayParams);
                }
            } 

            return HitTestResultBehavior.Continue; 
        } 

        internal HitTestResultBehavior HitTestChildren( 
            HitTestFilterCallback filterCallback,
            RayHitTestParameters rayParams)
        {
            return HitTestChildren(filterCallback, rayParams, this); 
        }
 
        ///  
        ///     Static helper used by ModelVisual3D and Viewport3DVisual to hit test
        ///     against their children collections. 
        /// 
        internal static HitTestResultBehavior HitTestChildren(
            HitTestFilterCallback filterCallback,
            RayHitTestParameters rayParams, 
            IVisual3DContainer container)
        { 
            if (container != null) 
            {
                int childrenCount = container.GetChildrenCount(); 

                for (int i = childrenCount - 1; i >= 0; i--)
                {
                    Visual3D child = container.GetChild(i); 

                    // Visuall3D.RayHitTest does not apply the Visual3D's Transform.  We need to 
                    // transform into the content's space before hit testing. 
                    Transform3D transform = child.Transform;
                    rayParams.PushVisualTransform(transform); 

                    // Perform the hit-test against the child.
                    HitTestResultBehavior result = child.RayHitTest(filterCallback, rayParams);
 
                    rayParams.PopTransform(transform);
 
                    if (result == HitTestResultBehavior.Stop) 
                    {
                        return HitTestResultBehavior.Stop; 
                    }
                }
            }
 
            return HitTestResultBehavior.Continue;
        } 
 
        internal void RayHitTestInternal(
            HitTestFilterCallback filterCallback, 
            RayHitTestParameters rayParams)
        {
            Model3D model = _visual3DModel;
 
            if (model != null)
            { 
                // If our Model3D hit test intersects anything we should return "this" Visual3D 
                // as the HitTestResult.VisualHit.
                rayParams.CurrentVisual = this; 

                model.RayHitTest(rayParams);
            }
        } 

        ///  
        ///     Generic "render changed" handler which sets IsDirtyForRender 
        ///     and propagates IsSubtreeDirtyForRender/Precompute.
        ///  
        internal void RenderChanged(object sender, EventArgs e)
        {
            PropagateFlags(
                this, 
                VisualFlags.IsSubtreeDirtyForPrecompute,
                VisualProxyFlags.IsSubtreeDirtyForRender); 
        } 

        ///  
        /// VisualContentBounds returns the bounding box for the contents of the current visual.
        /// 
        internal Rect3D VisualContentBounds
        { 
            get
            { 
                // Probably too restrictive. Let's see who wants it during OnRender. 
                VerifyAPIReadWrite();
 
                return GetContentBounds();
            }
        }
 
        /// 
        /// Visual2DContentBounds returns the 2D bounding box for the content of this 3D object.  The 2D bounding box 
        /// is the projection of the 3D content bounding box up to the nearest 2D visual that contains the Visual3D. 
        /// 
        [FriendAccessAllowed] 
        internal Rect Visual2DContentBounds
        {
            get
            { 
                VerifyAPIReadWrite();
                Rect contentBounds = Rect.Empty; 
 
                Viewport3DVisual viewport3DVisual = (Viewport3DVisual)VisualTreeHelper.GetContainingVisual2D(this);
                if (viewport3DVisual != null) { 
                    GeneralTransform3DTo2D transform = TransformToAncestor(viewport3DVisual);
                    contentBounds = transform.TransformBounds(VisualContentBounds);
                }
 
                return contentBounds;
            } 
        } 

        // Returns true if the content has something requiring realization 
        internal bool PrecomputeContent()
        {
            Model3D model = _visual3DModel;
            if (model != null) 
            {
                // The Visual3D may be dirty for precompute because of its 
                // children not because of its Content so we'll check before 
                // calling
                if (model._flags[Model3D.DirtyForPreComputeFlag]) 
                {
                    model.PreCompute();
                }
 
                return model._flags[Model3D.RequiresRealizationFlag];
            } 
 
            return false;
        } 

        internal Rect3D BBoxSubgraph
        {
            get 
            {
                if (CheckFlagsAnd(VisualFlags.IsSubtreeDirtyForPrecompute)) 
                { 
                    // force an update of the bounds cache
                    Rect3D transformedBBoxSubgraphIgnored; 
                    PrecomputeRecursive(out transformedBBoxSubgraphIgnored);
                }

                Debug_VerifyCachedSubgraphBounds(); 

                return _bboxSubgraph; 
            } 

        } 

        /// 
        /// Derived classes must override this method and return the bounding
        /// box of their content in the Visual's local space. 
        /// 
        internal Rect3D GetContentBounds() 
        { 
            Model3D model = _visual3DModel;
 
            if (model == null)
            {
                return Rect3D.Empty;
            } 

            if (!CheckFlagsAnd(VisualFlags.Are3DContentBoundsValid)) 
            { 
                _bboxContent = model.CalculateSubgraphBoundsOuterSpace();
                SetFlags(true, VisualFlags.Are3DContentBoundsValid); 
            }

            Debug_VerifyCachedContentBounds();
 
            return _bboxContent;
        } 
 
        /// 
        /// Returns the subgraph bounds in the Visual3D's outer coordinate space. 
        /// 
        internal Rect3D CalculateSubgraphBoundsOuterSpace()
        {
            Rect3D bounds = CalculateSubgraphBoundsInnerSpace(); 

            return M3DUtil.ComputeTransformedAxisAlignedBoundingBox(ref bounds, Transform); 
        } 

        ///  
        /// Returns the subgraph bounds in the Visual3D's inner coordinate space.
        /// 
        internal Rect3D CalculateSubgraphBoundsInnerSpace()
        { 
            return BBoxSubgraph;
        } 
 
        /// 
        /// VisualDescendantBounds returns the union of all of the content bounding 
        /// boxes for all of the descendants of the current visual, but not including
        /// the contents of the current visual.
        /// 
        internal Rect3D VisualDescendantBounds 
        {
            get 
            { 
                // Probably too restrictive. Let's see who wants it during OnRender.
                VerifyAPIReadWrite(); 

                return CalculateSubgraphBoundsInnerSpace();
            }
        } 

        // CS0536: Intreface implementation must be public or explicit so we re-expose 
        // the internal methods as an explicit implementation of an internal interface. 
        void IVisual3DContainer.VerifyAPIReadOnly() { this.VerifyAPIReadOnly(); }
        void IVisual3DContainer.VerifyAPIReadOnly(DependencyObject other) { this.VerifyAPIReadOnly(other); } 
        void IVisual3DContainer.VerifyAPIReadWrite() { this.VerifyAPIReadWrite(); }
        void IVisual3DContainer.VerifyAPIReadWrite(DependencyObject other) { this.VerifyAPIReadWrite(other); }

        ///  
        /// Applies various API checks
        ///  
        internal void VerifyAPIReadOnly() 
        {
            // Verify that we are executing on the right context 
            VerifyAccess();
        }

        ///  
        /// Applies various API checks
        ///  
        internal void VerifyAPIReadOnly(DependencyObject other) 
        {
            VerifyAPIReadOnly(); 

            if (other != null)
            {
                // Make sure the visual is on the same context as we are 
                MediaSystem.AssertSameContext(this, other);
            } 
        } 

        ///  
        /// Applies various API checks for read/write
        /// 
        internal void VerifyAPIReadWrite()
        { 
            VerifyAPIReadOnly();
 
            // Verify the correct access permissions 
            MediaContext.From(this.Dispatcher).VerifyWriteAccess();
        } 

        /// 
        /// Applies various API checks
        ///  
        internal void VerifyAPIReadWrite(DependencyObject other)
        { 
            VerifyAPIReadWrite(); 

            if (other != null) 
            {
                // Make sure the visual is on the same context as we are
                MediaSystem.AssertSameContext(this, other);
            } 
        }
 
        internal void SetParent(Visual newParent) 
        {
            _2DParent.SetValue(this, newParent); 
            _3DParent = null;

            Debug.Assert(InternalVisualParent == newParent);
        } 

        internal void SetParent(Visual3D newParent) 
        { 
            _2DParent.ClearValue(this);
            _3DParent = newParent; 

            Debug.Assert(InternalVisualParent == newParent);
        }
 
        /// 
        ///  Derived classes override this property to enable the Visual code to enumerate 
        ///  the Visual children. Derived classes need to return the number of children 
        ///  from this method.
        /// 
        ///    By default a Visual does not have any children.
        ///
        ///  Remark: During this virtual method the Visual tree must not be modified.
        ///  
        protected virtual int Visual3DChildrenCount
        { 
            get { return 0; } 
        }
 
        /// 
        ///   Derived class must implement to support Visual children. The method must return
        ///    the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1.
        /// 
        ///    By default a Visual does not have any children.
        /// 
        ///  Remark: 
        ///       Need to lock down Visual tree during the callbacks.
        ///       During this virtual call it is not valid to modify the Visual tree. 
        ///
        ///       It is okay to type this protected API to the 2D Visual.  The only 2D Visual with
        ///       3D childern is the Viewport3DVisual which is sealed.  -- [....] 01/17/06
        ///  
        protected virtual Visual3D GetVisual3DChild(int index)
        { 
           throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); 
        }
 
        /// 
        ///     Notifies the element that you have added a child.  The Element
        ///     will update the parent pointer, fire the correct events, etc.
        ///  
        void IVisual3DContainer.AddChild(Visual3D child)
        { 
            AddVisual3DChild(child); 
        }
 
        /// 
        ///     Notifies the element that you have removed a child.  The Element
        ///     will update the parent pointer, fire the correct events, etc.
        ///  
        void IVisual3DContainer.RemoveChild(Visual3D child)
        { 
            RemoveVisual3DChild(child); 
        }
 
        /// 
        ///     Gets the number of Visual3D children that the IVisual3DContainer
        ///     contains.
        ///  
        int IVisual3DContainer.GetChildrenCount()
        { 
            return Visual3DChildrenCount; 
        }
 
        /// 
        ///     Gets the index children of the IVisual3DContainer
        /// 
        Visual3D IVisual3DContainer.GetChild(int index) 
        {
            return GetVisual3DChild(index); 
        } 

        //------------------------------------------------------ 
        //
        //  DEBUG
        //
        //----------------------------------------------------- 

        #region DEBUG 
 
        [Conditional("DEBUG")]
        internal void Debug_VerifyBoundsEqual(Rect3D bounds1, Rect3D bounds2, string errorString) 
        {
            // The funny boolean logic below avoids asserts when the cached
            // bounds contain NaNs.  (NaN != NaN)
            bool boundsAreEqual = 
                !(bounds1.X < bounds2.X || bounds1.X > bounds2.X) &&
                !(bounds1.Y < bounds2.Y || bounds1.Y > bounds2.Y) && 
                !(bounds1.Z < bounds2.Z || bounds1.Z > bounds2.Z) && 
                !(bounds1.SizeX < bounds2.SizeX || bounds1.SizeX > bounds2.SizeX) &&
                !(bounds1.SizeY < bounds2.SizeY || bounds1.SizeY > bounds2.SizeY) && 
                !(bounds1.SizeZ < bounds2.SizeZ || bounds1.SizeZ > bounds2.SizeZ);

            Debug.Assert(boundsAreEqual, errorString);
        } 

        [Conditional("DEBUG")] 
        internal void Debug_VerifyCachedSubgraphBounds() 
        {
            Rect3D currentBounds = Rect3D.Empty; 
#if DEBUG
            currentBounds = Debug_CalculateSubgraphBounds();
#endif
            // currentBounds includes Transform so we need to 
            // temporarily transform _bboxSubgraph
            Rect3D cachedBounds = M3DUtil.ComputeTransformedAxisAlignedBoundingBox(ref _bboxSubgraph, Transform); 
 
            Debug_VerifyBoundsEqual(cachedBounds, currentBounds, "Cached bbox subgraph is incorrect!");
        } 

        [Conditional("DEBUG")]
        internal void Debug_VerifyCachedContentBounds()
        { 
            Model3D model = _visual3DModel;
 
            Debug.Assert(model != null); 

            Debug_VerifyBoundsEqual(model.CalculateSubgraphBoundsOuterSpace(), 
                                    _bboxContent, "Cached content bounds is incorrect!");
        }

// [Conditional] does not work on methods that return values 
#if DEBUG
        internal Rect3D Debug_CalculateSubgraphBounds() 
        { 
            Rect3D currentSubgraphBounds = GetContentBounds();
 
            for (int i = 0, count = Visual3DChildrenCount; i < count; i++)
            {
                currentSubgraphBounds.Union(
                    GetVisual3DChild(i).Debug_CalculateSubgraphBounds() 
                    );
            } 
 
            return M3DUtil.ComputeTransformedAxisAlignedBoundingBox(ref currentSubgraphBounds, Transform);
        } 
#endif

        #endregion DEBUG
 
        /// 
        /// Precompute pass. 
        ///  
        internal void PrecomputeRecursive(out Rect3D bboxSubgraph)
        { 
            if (CheckFlagsAnd(VisualFlags.IsSubtreeDirtyForPrecompute))
            {
                //
                // Track which subtrees have nodes that use realization caches. 
                //
 
                bool subTreeUsesRealizationCaches = false; 

                subTreeUsesRealizationCaches |= PrecomputeContent(); 

                //
                // Update the subgraph bounding box which includes the content bounds
                // and the bounds of our children. 
                //
 
                _bboxSubgraph = GetContentBounds(); 

                for (int i = 0, count = Visual3DChildrenCount; i < count; i++) 
                {
                    Visual3D child = GetVisual3DChild(i);

                    Rect3D bboxSubgraphChild; 
                    child.PrecomputeRecursive(out bboxSubgraphChild);
                    _bboxSubgraph.Union(bboxSubgraphChild); 
 
                    subTreeUsesRealizationCaches |=
                        child.CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches); 
                }

                //
                // Update the NodeInSubtreeUsesRealizationCaches bit. 
                //
 
                subTreeUsesRealizationCaches |= CheckFlagsAnd(VisualFlags.NodeUsesRealizationCaches); 
                SetFlags(subTreeUsesRealizationCaches, VisualFlags.NodeInSubtreeUsesRealizationCaches);
                SetFlags(false, VisualFlags.IsSubtreeDirtyForPrecompute); 
            }

            bboxSubgraph = M3DUtil.ComputeTransformedAxisAlignedBoundingBox(ref _bboxSubgraph, Transform);
       } 

        internal void RenderRecursive(RenderContext ctx) 
        { 
            DUCE.Channel channel = ctx.Channel;
            DUCE.ResourceHandle handle = DUCE.ResourceHandle.Null; 
            VisualProxyFlags flags = c_Model3DVisualProxyFlagsDirtyMask;

            //
            // Ensure that the resource for this Visual is sent to our current channel. 
            //
            bool isOnChannel = IsOnChannel(channel); 
            if (isOnChannel) 
            {
                // 
                // Good, we're already on channel. Get the handle and the flags.
                //

                handle = _proxy.GetHandle(channel); 
                flags = _proxy.GetFlags(channel);
            } 
            else 
            {
                // 
                // Create the visual resource on the current channel.
                //
                // Note: we need to update all set properties (the dirty
                //       bit mask is set by default). 
                //
 
                handle = ((DUCE.IResource)this).AddRefOnChannel(channel); 
            }
 
            //
            // Hookup content to the Visual
            //
 
            if ((flags & VisualProxyFlags.IsContentDirty) != 0)
            { 
                RenderContent(ctx, isOnChannel); 
            }
 
            //
            // Update the transform.
            //
 
            if ((flags & VisualProxyFlags.IsTransformDirty) != 0)
            { 
                Transform3D transform = Transform; 
                if (transform != null && InternalIsVisible)
                { 
                    //
                    // Set the new transform resource for this visual.  If transform is
                    // null we don't need to do this.  Also note that the old transform
                    // was disconnected in the Transform property setter. 
                    //
 
                    DUCE.Visual3DNode.SetTransform( 
                        handle,
                        ((DUCE.IResource)transform).AddRefOnChannel(channel), 
                        channel);
                }
                else if (!InternalIsVisible)
                { 
                    DUCE.Visual3DNode.SetTransform(
                        handle, 
                        ((DUCE.IResource)_zeroScale).AddRefOnChannel(channel), 
                        channel);
                } 
                else if (!isOnChannel) /* Transform == null */
                {
                    DUCE.Visual3DNode.SetTransform(
                        handle, 
                        DUCE.ResourceHandle.Null,
                        channel); 
                } 
            }
 
            // Visit children of this node -----------------------------------------------------------------------

            Debug.Assert((flags & VisualProxyFlags.IsContentNodeConnected) == 0,
                "Only HostVisuals are expected to have a content node."); 

            for (int i = 0; i < Visual3DChildrenCount; i++) 
            { 
                Visual3D child = GetVisual3DChild(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(ctx.Channel)) 
                    {
                        if (!child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent))
                        {
                            DUCE.Visual3DNode.InsertChildAt( 
                                handle,
                                ((DUCE.IResource)child).GetHandle(channel), 
                                /* iPosition = */ (uint)i, 
                                ctx.Channel);
 
                            child.SetFlags(channel, true, VisualProxyFlags.IsConnectedToParent);
                        }
                    }
                } 
            }
 
            // 
            // Finally, reset the dirty flags for this visual (at this point,
            // we have handled them all). 
            //

            SetFlags(channel, false, c_Model3DVisualProxyFlagsDirtyMask);
        } 

        ///  
        /// RenderContent is implemented to hook up the Visual3Ds content. 
        /// The implementer of this function can assert that the _hCompNode
        /// is valid on a channel when the function is executed. 
        /// 
        internal void RenderContent(RenderContext ctx, bool isOnChannel)
        {
            DUCE.Channel channel = ctx.Channel; 

            Debug.Assert(!CheckFlagsAnd(channel, VisualProxyFlags.IsContentConnected)); 
            Debug.Assert(IsOnChannel(channel)); 

            // 
            // Create the content on the channel.
            //

            if (_visual3DModel != null) 
            {
                // 
                // Attach the content to the visual resource 
                //
 
                DUCE.Visual3DNode.SetContent(
                    ((DUCE.IResource)this).GetHandle(channel),
                    ((DUCE.IResource)_visual3DModel).AddRefOnChannel(channel),
                    channel); 

                SetFlags(channel, true, VisualProxyFlags.IsContentConnected); 
            } 
            else if (isOnChannel) /* Model == null */
            { 
                DUCE.Visual3DNode.SetContent(
                    ((DUCE.IResource)this).GetHandle(channel),
                    DUCE.ResourceHandle.Null,
                    channel); 
            }
        } 
 
        /// 
        /// Returns true if the specified ancestor is really the ancestor of the 
        /// given descendant.
        /// 
        public bool IsAncestorOf(DependencyObject descendant)
        { 
            Visual visual;
            Visual3D visual3D; 
 
            VisualTreeUtils.AsNonNullVisual(descendant, out visual, out visual3D);
 
            // x86 branch prediction skips the branch on first encounter.  We favor 3D.
            if(visual != null)
            {
                return visual.IsDescendantOf(this); 
            }
 
            return visual3D.IsDescendantOf(this); 
        }
 
        /// 
        /// Returns true if the refernece Visual (this) is a descendant of the argument Visual.
        /// 
        public bool IsDescendantOf(DependencyObject ancestor) 
        {
            if (ancestor == null) 
            { 
                throw new ArgumentNullException("ancestor");
            } 

            VisualTreeUtils.EnsureVisual(ancestor);

            // Walk up the parent chain of the descendant untill we run out 
            // of 3D parents or we find the ancestor.
            Visual3D current = this; 
 
            while (current != null && current != ancestor)
            { 
                // If our 3D parent is null then continue walk in 2D
                if (current._3DParent == null)
                {
                    DependencyObject parent2D = current.InternalVisualParent; 

                    if (parent2D != null) 
                    { 
                        // The type has to be Visual because of the above if condition
                        return ((Visual)parent2D).IsDescendantOf(ancestor); 
                    }
                }

                current = current._3DParent; 
            }
 
            return current == ancestor; 
        }
 
        /// 
        ///     Walks up the Visual tree setting or clearing the given flags.  Unlike
        ///     PropagateFlags this does not terminate when it reaches node with
        ///     the flags already set.  It always walks all the way to the root. 
        /// 
        internal void SetFlagsToRoot(bool value, VisualFlags flag) 
        { 
            Visual3D current = this;
 
            do
            {
                current.SetFlags(value, flag);
 
                if (current._3DParent == null)
                { 
                    VisualTreeUtils.SetFlagsToRoot(InternalVisualParent, value, flag); 
                    return;
                } 

                current = current._3DParent;
            }
            while (current != null); 
        }
 
        ///  
        ///     Finds the first ancestor of the given element which has the given
        ///     flags set. 
        /// 
        internal DependencyObject FindFirstAncestorWithFlagsAnd(VisualFlags flag)
        {
            Visual3D current = this; 

            do 
            { 
                if (current.CheckFlagsAnd(flag))
                { 
                    // The other Visual crossed through this Visual's parent chain. Hence this is our
                    // common ancestor.
                    return current;
                } 

                if (current._3DParent == null) 
                { 
                    return VisualTreeUtils.FindFirstAncestorWithFlagsAnd(InternalVisualParent, flag);
                } 

                current = current._3DParent;
            }
            while (current != null); 

            return null; 
        } 

        ///  
        /// Finds the common ancestor of two Visuals.
        /// 
        /// Returns the common ancestor if the Visuals have one or otherwise null.
        /// If the argument is null. 
        public DependencyObject FindCommonVisualAncestor(DependencyObject otherVisual)
        { 
            VerifyAPIReadOnly(otherVisual); 

            if (otherVisual == null) 
            {
                throw new System.ArgumentNullException("otherVisual");
            }
 
            // Since we can't rely on code running in the CLR, we need to first make sure
            // that the FindCommonAncestor flag is not set. It is enought to ensure this 
            // on one path to the root Visual. 

            // 



 
            SetFlagsToRoot(false, VisualFlags.FindCommonAncestor);
 
            // Walk up the other visual's parent chain and set the FindCommonAncestor flag. 
            VisualTreeUtils.SetFlagsToRoot(otherVisual, true, VisualFlags.FindCommonAncestor);
 
            // Now see if the other Visual's parent chain crosses our parent chain.
            return FindFirstAncestorWithFlagsAnd(VisualFlags.FindCommonAncestor);
        }
 
        /// 
        /// Override this function in derived classes to release unmanaged resources during Dispose 
        /// and during removal of a subtree. 
        /// 
        internal void FreeDUCEResources(DUCE.Channel channel) 
        {
            Transform3D transform = Transform;
            if (!CheckFlagsAnd(channel, VisualProxyFlags.IsTransformDirty))
            { 
                if (InternalIsVisible)
                { 
                    if (transform != null) 
                    {
                        ((DUCE.IResource)transform).ReleaseOnChannel(channel); 
                    }
                }
                else
                { 
                    ((DUCE.IResource)_zeroScale).ReleaseOnChannel(channel);
                } 
            } 

            Model3D model = _visual3DModel; 
            if ((model != null) && (!CheckFlagsAnd(channel, VisualProxyFlags.IsContentDirty)))
            {
                ((DUCE.IResource)model).ReleaseOnChannel(channel);
            } 

            Debug.Assert(IsOnChannel(channel)); 
            Debug.Assert(!CheckFlagsAnd(channel, VisualProxyFlags.IsContentNodeConnected)); 

            _proxy.ReleaseOnChannel(channel); 
        }

        void DUCE.IResource.ReleaseOnChannel(DUCE.Channel channel)
        { 
            ReleaseOnChannelCore(channel);
        } 
 
        internal void ReleaseOnChannelCore(DUCE.Channel channel)
        { 
            if (!IsOnChannel(channel))
            {
                return;
            } 

            // at this point the tree is not connected any more. 
            SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent); 

            FreeDUCEResources(channel); 

            for (int i = 0; i < Visual3DChildrenCount; i++)
            {
                Visual3D child = GetVisual3DChild(i); 
                ((DUCE.IResource)child).ReleaseOnChannel(channel);
            } 
        } 

        ///  
        /// Disconnects a resource attached to this visual.
        /// 
        internal void DisconnectAttachedResource(
            VisualProxyFlags correspondingFlag, 
            DUCE.IResource attachedResource)
        { 
            // 
            // Iterate over the channels this visual is being marshaled to
            // 

            for (int i = 0; i < _proxy.Count; i++)
            {
                VisualProxyFlags flags = _proxy.GetFlags(i); 

                if ((flags & correspondingFlag) == 0) 
                { 
                    DUCE.Channel channel = _proxy.GetChannel(i);
 
                    //
                    // Set the flag so that during render we send
                    // update to the compositor.
                    // 
                    SetFlags(channel, true, correspondingFlag);
 
                    if (correspondingFlag == VisualProxyFlags.IsContentDirty) 
                    {
                        _proxy.SetFlags(i, false, VisualProxyFlags.IsContentConnected); 
                    }

                    //
                    // Add this resource to the queue for delayed-removal. 
                    //
                    channel.AddToRemoveAndReleaseQueue( 
                        null, 
                        attachedResource);
                } 
            }
        }

        internal void UpdateRealizations(RealizationContext rc) 
        {
            Debug.Assert(CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches)); 
 
            Matrix3DStack stack3D = rc.Transform3DStack;
            Transform3D transform = Transform; 

            if (transform != null)
            {
                stack3D.Push(transform.Value); 
            }
 
            Model3D model = _visual3DModel; 
            // It's possible that NodeInSubtreeUsesRealizationCaches is 'true' for
            // one of the children but not the Model so we still check the ProtectedContent 
            if (model != null && model._flags[Model3D.RequiresRealizationFlag])
            {
                model.MarkVisibleRealizations(rc);
            } 

 
            // should this know about children? 
            for (int i = 0; i < Visual3DChildrenCount; i++)
            { 
                Visual3D child = GetVisual3DChild(i);
                if (child.CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches))
                {
                    child.UpdateRealizations(rc); 
                }
            } 
 
            if (transform != null)
            { 
                stack3D.Pop();
            }
        }
 
        // Normally the inheritence context is the same as our parent.  When it differs,
        // we store the value in the _inheritanceContext UncommonField.  See comments 
        // on the _inheritanceContext and UseParentAsContext members for more info. 
        internal override DependencyObject InheritanceContext
        { 
            get
            {
                DependencyObject value = _inheritanceContext.GetValue(this);
 
                if (value == UseParentAsContext)
                { 
                    return InternalVisualParent; 
                }
 
                return value;
            }
        }
 
        internal override void AddInheritanceContext(DependencyObject context, DependencyProperty property)
        { 
            base.AddInheritanceContext(context, property); 

            // Call local helper 
            AddOrRemoveInheritanceContext(context);
        }

        internal override void RemoveInheritanceContext(DependencyObject context, DependencyProperty property) 
        {
            base.RemoveInheritanceContext(context, property); 
 
            // Call local helper
            AddOrRemoveInheritanceContext(null); 
        }

        // Local helping for adding or removing an inheritance context
        private void AddOrRemoveInheritanceContext(DependencyObject newInheritanceContext) 
        {
            // If we are using our parent as our inheritance context the InheritanceContext 
            // property will already be returning the new context, but we still need to treat 
            // this as a change so we notify our dependants.
            bool contextChanged = 
                InheritanceContext != newInheritanceContext ||
                (_inheritanceContext.GetValue(this) == UseParentAsContext &&
                    newInheritanceContext == InternalVisualParent);
 
            if (contextChanged)
            { 
                // Pick up the new context 
                SetInheritanceContext(newInheritanceContext);
                OnInheritanceContextChanged(EventArgs.Empty); 
            }
        }

        internal override bool HasMultipleInheritanceContexts 
        {
            get { return base.HasMultipleInheritanceContexts; } 
        } 

        internal override void OnInheritanceContextChangedCore(EventArgs args) // ancestor changed 
        {
            base.OnInheritanceContextChangedCore(args);

            for (int i = 0; i < Visual3DChildrenCount; i++) 
            {
                DependencyObject child = GetVisual3DChild(i); 
 
                Debug.Assert(child.InheritanceContext == this,
                    "How did a child get inserted without propagating our inheritance context?"); 

                child.OnInheritanceContextChanged(args);
            }
        } 

        #endregion Internal Methods 
 
        // -------------------------------------------------------------------
        // 
        //   Visual-to-Visual Transforms
        //
        // --------------------------------------------------------------------
 
        #region Visual-to-Visual Transforms
 
        ///  
        /// Returns a transform that can be used to transform coordinates from this
        /// node to the specified ancestor, or null if the transformation cannot be created. 
        /// 2D is allowed to be between the 3D nodes.
        /// 
        /// 
        /// If ancestor is null. 
        /// 
        ///  
        /// If the ancestor Visual3D is not a ancestor of Visual3D. 
        /// 
        /// If the Visual3Ds are not connected. 
        public GeneralTransform3D TransformToAncestor(Visual3D ancestor)
        {
            if (ancestor == null)
            { 
                throw new ArgumentNullException("ancestor");
            } 
 
            VerifyAPIReadOnly(ancestor);
 
            return InternalTransformToAncestor(ancestor, false);
        }

 
        /// 
        /// Returns a transform that can be used to transform coordinates from this 
        /// node to the specified descendant, or null if the transform from descendant to "this" 
        /// is non-invertible.  This is the case when 2D is between the nodes.
        /// 
        /// 
        /// 
        /// If the reference Visual3D is not a ancestor of the descendant Visual3D.
        ///  
        /// If the descendant argument is null.
        /// If the Visual3Ds are not connected. 
        public GeneralTransform3D TransformToDescendant(Visual3D descendant) 
        {
            if (descendant == null) 
            {
                throw new ArgumentNullException("descendant");
            }
 
            VerifyAPIReadOnly(descendant);
 
            return descendant.InternalTransformToAncestor(this, true); 
        }
 
        /// 
        /// Returns the transform or the inverse transform between this visual and the specified ancestor.
        /// If inverse is requested but does not exist (if the transform is not invertible), null is returned.
        ///  
        /// Ancestor visual.
        /// Returns inverse if this argument is true. 
        private GeneralTransform3D InternalTransformToAncestor(Visual3D ancestor, bool inverse) 
        {
            Debug.Assert(ancestor != null); 

            // used to track if all the collected transforms on the way to the ancestor were valid
            bool success = true;
 
            DependencyObject g = this;
            Visual3D lastVisual3D = null; 
 
            Matrix3D m = Matrix3D.Identity;
            GeneralTransform3DGroup group = null; 

            // This while loop will walk up the visual tree until we encounter the ancestor.
            // As it does so, it will accumulate the descendent->ancestor transform.
            // In most cases, this is simply a matrix, though if we encounter a 2D node we need to 
            // transform from 3D out in to 2D and then back in to 3D and continue the parent walk.
            // We will accumulate the current transform in a matrix until we encounter a 2D parent, 
            // at which point we will add the matrix's current value and the transform from 3D to 2D to 3D 
            // to the GeneralTransform3DGroup and continue to accumulate further transforms in the matrix again.
            // At the end of this loop, we will have 0 or more transforms in the GeneralTransform3DGroup 
            // and the matrix which, if not identity, should be appended to the GeneralTransform3DGroup.
            // If, as is commonly the case, this loop terminates without encountering a 2D parent
            // we will simply use the Matrix3D.
 
            while ((VisualTreeHelper.GetParent(g) != null) && (g != ancestor))
            { 
                Visual3D gAsVisual3D = g as Visual3D; 
                if (gAsVisual3D != null)
                { 
                    Transform3D transform = gAsVisual3D.Transform;
                    if (transform != null)
                    {
                        transform.Append(ref m); 
                    }
 
                    lastVisual3D = gAsVisual3D; 
                    g = VisualTreeHelper.GetParent(gAsVisual3D);
                } 
                else
                {
                    if (group == null)
                    { 
                        group = new GeneralTransform3DGroup();
                    } 
 
                    group.Children.Add(new MatrixTransform3D(m));
                    m = Matrix3D.Identity; 

                    // construct the 3D to 2D to 3D transform
                    Visual gAsVisual = g as Visual;
                    GeneralTransform3DTo2D transform3DTo2D = lastVisual3D.TransformToAncestor(gAsVisual); 

                    // now find the 3D parent of the 2D object 
                    Visual3D containing3DParent = VisualTreeHelper.GetContainingVisual3D(gAsVisual); 

                    // if containing3DParent is null, then the ancestor parameter is not really an ancestor 
                    // break out of the loop to allow it to fail
                    if (containing3DParent == null)
                    {
                        break; 
                    }
 
                    GeneralTransform2DTo3D transform2DTo3D = gAsVisual.TransformToAncestor(containing3DParent); 

                    // if either transform ends up being null then we don't have a transform 
                    if (transform3DTo2D == null || transform2DTo3D == null)
                    {
                        // we don't want to break here because although we own't be able to create a valid transformation
                        // we also want to throw an exception if the ancestor passed in is not a valid ancestor.  We then 
                        // continue the tree walk to make sure.
                        success = false; 
                    } 
                    else
                    { 
                        group.Children.Add(new GeneralTransform3DTo2DTo3D(transform3DTo2D, transform2DTo3D));
                    }

                    // the last visual3D found is where we continue the search 
                    g = containing3DParent;
                } 
            } 

            if (g != ancestor) 
            {
                throw new System.InvalidOperationException(SR.Get(inverse ? SRID.Visual_NotADescendant : SRID.Visual_NotAnAncestor));
            }
 
            // construct the generaltransform3d to return and invert it if necessary
            GeneralTransform3D finalTransform = null; 
 
            // if we successfully found a transform then we can create it here, otherwise finalTransform stays null
            if (success) 
            {
                if (group != null)
                {
                    finalTransform = group; 
                }
                else 
                { 
                    finalTransform = new MatrixTransform3D(m);
                } 

                if (inverse)
                {
                    finalTransform = finalTransform.Inverse; 
                }
            } 
 
            if (finalTransform != null)
            { 
                finalTransform.Freeze();
            }

            return finalTransform; 
        }
 
        ///  
        /// Returns a transform that can be used to transform coordinate from this
        /// node to the specified ancestor, or null if the transform does not exist. 
        /// This transform will take a 3D point, and then project it in to 2D space.
        /// The resulting point is the transformed 3D point in the coordinate space
        /// of the given ancestor.
        /// 
        /// 
        ///  
        /// If ancestor is null. 
        /// 
        ///  
        /// If the ancestor Visual is not an ancestor of this.
        /// 
        /// If the Visual3D and Visual are not connected.
        public GeneralTransform3DTo2D TransformToAncestor(Visual ancestor) 
        {
            if (ancestor == null) 
            { 
                throw new ArgumentNullException("ancestor");
            } 

            VerifyAPIReadOnly(ancestor);

            return InternalTransformToAncestor(ancestor); 
        }
 
        ///  
        /// Provides the transform between this visual3D and the specified ancestor, or null
        /// if the transform does not exist. 
        ///
        /// 
        /// Ancestor visual.
        /// The transform from 3D to 2D 
        internal GeneralTransform3DTo2D InternalTransformToAncestor(Visual ancestor)
        { 
            Debug.Assert(ancestor != null); 

            // get the transform out of 3D and in to 2D 
            Viewport3DVisual containingViewport;
            Matrix3D projectionTransform;

            if (!M3DUtil.TryTransformToViewport3DVisual(this, out containingViewport, out projectionTransform)) 
            {
                return null; 
            } 

            // get the transform from the Viewport3DVisual to the ancestor 
            GeneralTransform transformIn2D = containingViewport.TransformToAncestor(ancestor);

            // package the two up in the transformTo2D
            GeneralTransform3DTo2D result = new GeneralTransform3DTo2D(projectionTransform, transformIn2D); 
            result.Freeze();
 
            return result; 
        }
 
        #endregion Visual-to-Visual Transforms

        //-----------------------------------------------------
        // 
        //  Internal Properties
        // 
        //------------------------------------------------------ 

        #region Internal Properties 

        internal DependencyObject InternalVisualParent
        {
            get 
            {
                if (_3DParent != null) 
                { 
                    Debug.Assert(_2DParent.GetValue(this) == null,
                        "Only one parent pointer should be set at a time."); 

                    return _3DParent;
                }
 
                DependencyObject parent2D = _2DParent.GetValue(this);
 
                Debug.Assert(parent2D == null || parent2D is Viewport3DVisual, 
                    "The only acceptable 2D parent for a Visual3D is a Viewport3DVisual.");
 
                return parent2D;
            }
        }
 
        internal int ParentIndex
        { 
            get { return _parentIndex; } 
            set { _parentIndex = value; }
        } 

        // Are we in the process of iterating the visual children.
        // This flag is set during a descendents walk, for property invalidation.
        internal bool IsVisualChildrenIterationInProgress 
        {
            [FriendAccessAllowed] 
            get { return CheckFlagsAnd(VisualFlags.IsVisualChildrenIterationInProgress); } 

            [FriendAccessAllowed] 
            set { SetFlags(value, VisualFlags.IsVisualChildrenIterationInProgress); }
        }

        #endregion Internal Properties 

        // -------------------------------------------------------------------- 
        // 
        //   Visual flags manipulation
        // 
        // -------------------------------------------------------------------

        #region Visual flags manipulation
 
        /// 
        /// SetFlagsOnAllChannels is used to set or unset one 
        /// or multiple flags on all channels this visual is 
        /// marshaled to.
        ///  
        internal void SetFlagsOnAllChannels(
            bool value,
            VisualProxyFlags flagsToChange)
        { 
            _proxy.SetFlagsOnAllChannels(
                value, 
                flagsToChange); 
        }
 
        /// 
        /// SetFlags is used to set or unset one or multiple flags on a given channel.
        /// 
        internal void SetFlags( 
            DUCE.Channel channel,
            bool value, 
            VisualProxyFlags flagsToChange) 
        {
            _proxy.SetFlags( 
                channel,
                value,
                flagsToChange);
        } 

        ///  
        /// SetFlags is used to set or unset one or multiple node flags on the node. 
        /// 
        internal void SetFlags(bool value, VisualFlags Flags) 
        {
            _flags = value ? (_flags | Flags) : (_flags & (~Flags));
        }
 
        /// 
        /// CheckFlagsOnAllChannels returns true if all flags in 
        /// the bitmask flags are set on all channels this visual is 
        /// marshaled to.
        ///  
        /// 
        /// If there aren't any bits set on the specified flags
        /// the method returns true.
        ///  
        internal bool CheckFlagsOnAllChannels(VisualProxyFlags flagsToCheck)
        { 
            return _proxy.CheckFlagsOnAllChannels(flagsToCheck); 
        }
 
        /// 
        /// CheckFlagsAnd returns true if all flags in the bitmask flags
        /// are set on a given channel.
        ///  
        /// 
        /// If there aren't any bits set on the specified flags 
        /// the method returns true. 
        /// 
        internal bool CheckFlagsAnd( 
            DUCE.Channel channel,
            VisualProxyFlags flagsToCheck)
        {
            return (_proxy.GetFlags(channel) & flagsToCheck) == flagsToCheck; 
        }
 
        ///  
        /// CheckFlagsAnd returns true if all flags in the bitmask flags are set on the node.
        ///  
        /// If there aren't any bits set on the specified flags the method
        /// returns true
        internal bool CheckFlagsAnd(VisualFlags flags)
        { 
            return (_flags & flags) == flags;
        } 
 
        /// 
        /// Returns the child at index "index" (in most cases this will be 
        /// a Visual, but it some cases, Viewport3DVisual for instance,
        /// this is a Visual3D).
        ///
        /// Used only by VisualTreeHelper. 
        /// 
        internal virtual DependencyObject InternalGet2DOr3DVisualChild(int index) 
        { 
            // Call the right virtual method.
            return GetVisual3DChild(index); 
        }

        /// 
        /// Returns the number of children of this object (in most cases this will be 
        /// the number of Visuals, but it some cases, Viewport3DVisual for instance,
        /// this is the number of Visual3Ds). 
        /// 
        /// Used only by VisualTreeHelper.
        ///  
        internal virtual int InternalVisual2DOr3DChildrenCount
        {
            get
            { 
                // Call the right virtual method.
                return Visual3DChildrenCount; 
            } 
        }
 
        /// 
        /// Checks if any of the specified flags is set on a given channel.
        /// 
        ///  
        /// If there aren't any bits set on the specified flags
        /// the method returns true. 
        ///  
        internal bool CheckFlagsOr(
            DUCE.Channel channel, 
            VisualProxyFlags flagsToCheck)
        {
            return (_proxy.GetFlags(channel) & flagsToCheck) != VisualProxyFlags.None;
        } 

        ///  
        /// Checks if any of the specified flags is set on the node. 
        /// 
        /// If there aren't any bits set on the specified flags the method 
        /// returns true
        internal bool CheckFlagsOr(VisualFlags flags)
        {
            return (flags == 0) || ((_flags & flags) > 0); 
        }
 
        ///  
        ///     Check all the children for a bit.
        ///  
        internal static bool DoAnyChildrenHaveABitSet(Visual3D pe,
                                                      VisualFlags flag)
        {
 
            int count = pe.InternalVisual2DOr3DChildrenCount;
            for (int i = 0; i < count; i++) 
            { 
                DependencyObject child = pe.InternalGet2DOr3DVisualChild(i);
 
                Visual v = null;
                Visual3D v3D = null;
                VisualTreeUtils.AsNonNullVisual(child, out v, out v3D);
 
                if (v != null && v.CheckFlagsAnd(flag))
                { 
                    return true; 
                }
                else if (v3D != null && v3D.CheckFlagsAnd(flag)) 
                {
                    return true;
                }
            } 

            return false; 
        } 

        ///  
        /// Propagates the flags up to the root.
        /// 
        /// 
        /// The walk stops on a node with all of the required flags set. 
        /// 
        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.NodeIsVisualBrushRoot), 
                    "Visual3Ds should never be the root of a VisualBrush.");

                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;
            } 
        }
 
        #endregion Visual flags manipulation 

        //------------------------------------------------------ 
        //
        //  Private Methods
        //
        //----------------------------------------------------- 

        #region Private Methods 
 
        private void SetInheritanceContext(DependencyObject newInheritanceContext)
        { 
            if (newInheritanceContext == InternalVisualParent)
            {
                _inheritanceContext.ClearValue(this);
 
                Debug.Assert(_inheritanceContext.GetValue(this) == UseParentAsContext,
                    "Clearing the _inheritanceContext uncommon field should put us in the UseParentAsContext state."); 
            } 
            else
            { 
                _inheritanceContext.SetValue(this, newInheritanceContext);
            }
        }
 
        #endregion Private Methods
 
        //----------------------------------------------------- 
        //
        //  Internal Fields 
        //
        //-----------------------------------------------------

        #region Internal Fields 

        internal VisualProxy _proxy; 
 
        #endregion Internal Fields
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
 
        #region Private Fields 

        // If the parent of the Visual3D is another Visual3D we store the parent in the _3DParent field. 
        // If the parent is a 2D node (as is the case when this is the root of a Viewport3DVisual) we
        // store the parent in an UncommonField.  Both fields must be considered when determining
        // the parent of this node.
        private static readonly UncommonField _2DParent = 
            new UncommonField(/* defaultValue = */ null);
 
        // Sentinel value we use to differentiate between a null inheritance context stored in the 
        // _inheritanceContext uncommon field and "empty", meaning use the parent as context.
        private static readonly DependencyObject UseParentAsContext = new DependencyObject(); 

        // Normally the inheritance context is the same as the parent, except when we are parent to
        // a Viewport3D visual, in which case we use this uncommon field to store are alternate context.
        private static readonly UncommonField _inheritanceContext = 
            new UncommonField(/* defaultValue = */ UseParentAsContext);
 
        private static readonly UncommonField AncestorChangedEventField 
            = new UncommonField();
 
        private Visual3D _3DParent;
        private int _parentIndex = -1;

        private VisualFlags _flags; 

        // Untransformed *cached* content bounds. Do not access it directly -- instead 
        // use GetContentBounds() 
        private Rect3D _bboxContent;
 
        // Untransformed *cached* subgraph bounds. Do not access it directly -- instead
        // use the BBoxSubgraph property.
        private Rect3D _bboxSubgraph = Rect3D.Empty;
 
        private bool _internalIsVisible;
 
        private static readonly ScaleTransform3D _zeroScale = new ScaleTransform3D(0, 0, 0); 

        private Model3D _visual3DModel; 

        #endregion Private Fields

        //------------------------------------------------------ 
        //
        //  Protected Fields 
        // 
        //------------------------------------------------------
 
        #region Protected Fields

        #endregion Protected Fields
 
    }
} 
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK