Click here to Skip to main content
15,886,199 members
Articles / Desktop Programming / WPF

D3dScenePresenter - How to present and manipulate a 3D scene using MDX

Rate me:
Please Sign up or sign in to vote.
4.57/5 (14 votes)
15 Feb 2013CPOL14 min read 45.1K   1.6K   25  
This article shows how we can present a 3D scene and, perform common operations (zoom, rotate, move, zoom to specific region, adjust the camera to view the whole of the scene, and pick a 3D shape on a specific region on the rendered surface) on it, using Managed DirectX.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using MdxScene.Cameras;
using MdxScene.Shapes;
using MdxWpfInteroperability;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;

namespace MdxScene.Controls
{
    public class D3dScenePresenter : D3dHost
    {
        #region inner structures

        public enum CameraOperation
        {
            None,
            Zoom,
            UniformZoom,
            XyMove,
            ZMove,
            TargetXyRotate,
            TargetZRotate,
            CameraXyRotate,
            CameraZRotate,
            ZoomToRegion,
            UniformZoomToRegion
        }

        public class MouseMoveOperation
        {
            public MouseMoveOperation()
            {
                Operation = CameraOperation.None;

                LeftButtonState = MouseButtonState.Released;
                MiddleButtonState = MouseButtonState.Released;
                RightButtonState = MouseButtonState.Released;
                XButton1State = MouseButtonState.Released;
                XButton2State = MouseButtonState.Released;

                Modifiers = ModifierKeys.None;
            }

            #region Properties

            public CameraOperation Operation { get; set; }

            #region Mouse buttons state
            public MouseButtonState LeftButtonState { get; set; }
            public MouseButtonState MiddleButtonState { get; set; }
            public MouseButtonState RightButtonState { get; set; }
            public MouseButtonState XButton1State { get; set; }
            public MouseButtonState XButton2State { get; set; }
            #endregion

            public ModifierKeys Modifiers { get; set; }

            #endregion

            public bool IsCurrentStateFitting()
            {
                return IsMouseCurrentStateFitting() && IsKeyboardCurrentStateFitting();
            }

            public bool IsMouseCurrentStateFitting()
            {
                return Mouse.LeftButton == LeftButtonState &&
                       Mouse.MiddleButton == MiddleButtonState &&
                       Mouse.RightButton == RightButtonState &&
                       Mouse.XButton1 == XButton1State &&
                       Mouse.XButton2 == XButton2State;
            }

            public bool IsKeyboardCurrentStateFitting()
            {
                ModifierKeys currentModifiers = ModifierKeys.None;

                if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
                {
                    currentModifiers |= ModifierKeys.Shift;
                }

                if(Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))
                {
                    currentModifiers |= ModifierKeys.Alt;
                }

                if(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                {
                    currentModifiers |= ModifierKeys.Control;
                }

                if (Keyboard.IsKeyDown(Key.LWin) || Keyboard.IsKeyDown(Key.RWin))
                {
                    currentModifiers |= ModifierKeys.Windows;
                }

                return currentModifiers == Modifiers;
            }
        }

        protected class RegionIndicatorAdorner : Adorner
        {
            public RegionIndicatorAdorner(UIElement adornedElement)
                : base(adornedElement)
            {
                Visibility = Visibility.Collapsed;

                IsHitTestVisible = false;

                FillBrush = new SolidColorBrush(new Color
                                                    {
                                                        A = 128,
                                                        R = 0,
                                                        G = 0,
                                                        B = 0
                                                    });

                BorderPen = new Pen(new SolidColorBrush(new Color
                                                            {
                                                                A = 128,
                                                                R = 255,
                                                                G = 255,
                                                                B = 255
                                                            }), 2)
                                {
                                    DashStyle = new DashStyle(new double[] {5, 5}, 0)
                                };
            }

            #region Properties

            public double RectangleTop { get; set; }
            public double RectangleLeft { get; set; }
            public double RectangleWidth { get; set; }
            public double RectangleHeight { get; set; }

            public double ActualRectangleTop { get; private set; }
            public double ActualRectangleLeft { get; private set; }

            #region ActualRectangleWidth
            private double _actualRectangleWidth;
            public double ActualRectangleWidth { get { return _actualRectangleWidth; } }
            #endregion

            #region ActualRectangleHeight
            private double _actualRectangleHeight;
            public double ActualRectangleHeight { get { return _actualRectangleHeight; } }
            #endregion

            public bool KeepAspectRatio { get; set; }

            public Brush FillBrush { get; set; }
            public Pen BorderPen { get; set; }

            #endregion

            protected override void OnRender(DrawingContext drawingContext)
            {                
                _actualRectangleWidth = RectangleWidth;
                _actualRectangleHeight = RectangleHeight;

                if (KeepAspectRatio)
                {
                    AdjustActualSize(ref _actualRectangleWidth, ref _actualRectangleHeight);
                }

                ActualRectangleTop = _actualRectangleHeight > 0 ? RectangleTop : RectangleTop + _actualRectangleHeight;
                ActualRectangleLeft = _actualRectangleWidth > 0 ? RectangleLeft : RectangleLeft + _actualRectangleWidth;

                Width = Math.Abs(_actualRectangleWidth);
                Height = Math.Abs(_actualRectangleHeight);

                Rect r = new Rect(ActualRectangleLeft, ActualRectangleTop, Width, Height);

                drawingContext.DrawRectangle(FillBrush, BorderPen, r);
            }

            private void AdjustActualSize(ref double actualRectangleWidth, ref double actualRectangleHeight)
            {
                Rectangle adornedRectangle = AdornedElement as Rectangle;
                if (null == adornedRectangle)
                {
                    return;
                }

                double relativeWidth = Math.Abs(actualRectangleWidth/adornedRectangle.ActualWidth);
                double relativeHeight = Math.Abs(actualRectangleHeight/adornedRectangle.ActualHeight);

                if (relativeWidth < relativeHeight)
                {
                    actualRectangleHeight *= (relativeWidth/relativeHeight);
                }
                else
                {
                    actualRectangleWidth *= (relativeHeight/relativeWidth);
                }
            }
        }

        #endregion
        
        protected RegionIndicatorAdorner _regionIndicatorAdorner;

        #region Constructors
        public D3dScenePresenter()
        {
            InitActions();
        }

        static D3dScenePresenter()
        {
            CommandBinding adjustCameraViewBinding =
                new CommandBinding(AdjustCameraViewCommand, ExecuteAdjustCameraViewCommand,
                                   CanExecuteAdjustCameraViewCommand);
            CommandManager.RegisterClassCommandBinding(typeof (D3dScenePresenter), adjustCameraViewBinding);

            CommandBinding horizontalZoomCommandBinding =
                new CommandBinding(HorizontalZoomCommand, ExecuteHorizontalZoomCommand, CanExecuteHorizontalZoomCommand);
            CommandManager.RegisterClassCommandBinding(typeof (D3dScenePresenter), horizontalZoomCommandBinding);

            CommandBinding verticalZoomCommandBinding =
                new CommandBinding(VerticalZoomCommand, ExecuteVerticalZoomCommand, CanExecuteVerticalZoomCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), verticalZoomCommandBinding);

            CommandBinding uniformZoomCommandBinding =
                new CommandBinding(UniformZoomCommand, ExecuteUniformZoomCommand, CanExecuteUniformZoomCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), uniformZoomCommandBinding);

            CommandBinding horizontalMoveCommandBinding =
                new CommandBinding(HorizontalMoveCommand, ExecuteHorizontalMoveCommand, CanExecuteHorizontalMoveCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), horizontalMoveCommandBinding);

            CommandBinding verticalMoveCommandBinding =
                new CommandBinding(VerticalMoveCommand, ExecuteVerticalMoveCommand, CanExecuteVerticalMoveCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), verticalMoveCommandBinding);

            CommandBinding moveAtLookDirectionCommandBinding =
                new CommandBinding(MoveAtLookDirectionCommand, ExecuteMoveAtLookDirectionCommand,
                                   CanExecuteMoveAtLookDirectionCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), moveAtLookDirectionCommandBinding);

            CommandBinding rotateCameraAroundXAxisCommandBinding =
                new CommandBinding(RotateCameraAroundXAxisCommand, ExecuteRotateCameraAroundXAxisCommand,
                                   CanExecuteRotateCameraAroundXAxisCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), rotateCameraAroundXAxisCommandBinding);

            CommandBinding rotateCameraAroundYAxisCommandBinding =
                new CommandBinding(RotateCameraAroundYAxisCommand, ExecuteRotateCameraAroundYAxisCommand,
                                   CanExecuteRotateCameraAroundYAxisCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), rotateCameraAroundYAxisCommandBinding);

            CommandBinding rotateCameraAroundZAxisCommandBinding =
                new CommandBinding(RotateCameraAroundZAxisCommand, ExecuteRotateCameraAroundZAxisCommand,
                                   CanExecuteRotateCameraAroundZAxisCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), rotateCameraAroundZAxisCommandBinding);

            CommandBinding rotateTargetAroundXAxisCommandBinding =
                new CommandBinding(RotateTargetAroundXAxisCommand, ExecuteRotateTargetAroundXAxisCommand,
                                   CanExecuteRotateTargetAroundXAxisCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), rotateTargetAroundXAxisCommandBinding);

            CommandBinding rotateTargetAroundYAxisCommandBinding =
                new CommandBinding(RotateTargetAroundYAxisCommand, ExecuteRotateTargetAroundYAxisCommand,
                                   CanExecuteRotateTargetAroundYAxisCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), rotateTargetAroundYAxisCommandBinding);

            CommandBinding rotateTargetAroundZAxisCommandBinding =
                new CommandBinding(RotateTargetAroundZAxisCommand, ExecuteRotateTargetAroundZAxisCommand,
                                   CanExecuteRotateTargetAroundZAxisCommand);
            CommandManager.RegisterClassCommandBinding(typeof(D3dScenePresenter), rotateTargetAroundZAxisCommandBinding);

        }
        #endregion

        protected override void OnLoaded(object sender, RoutedEventArgs e)
        {
            base.OnLoaded(sender, e);

            InvalidateScene();

            if (null != D3dRegion)
            {
                AdornerLayer d3dRegionAdornerLayer = AdornerLayer.GetAdornerLayer(D3dRegion);
                if (null != d3dRegionAdornerLayer)
                {
                    _regionIndicatorAdorner = new RegionIndicatorAdorner(D3dRegion)
                                                  {
                                                      FillBrush = RegionIndicatorFillBrush,
                                                      BorderPen = RegionIndicatorBorderPen
                                                  };

                    d3dRegionAdornerLayer.Add(_regionIndicatorAdorner);
                }
            }
        }

        protected override void OnD3dDeviceFailure(Exception ex)
        {
            base.OnD3dDeviceFailure(ex);

            if (IsLoaded)
            {
                InvalidateScene();
            }
        }

        #region InitActions
        protected Point _lastSurfaceMousePosition;

        private void InitActions()
        {
            D3dSurfaceMouseMove += OnD3dSurfaceMouseMove;
            D3dSurfaceMouseEnter += OnD3dSurfaceMouseEnter;
            D3dSurfaceMouseLeave += OnD3dSurfaceMouseLeave;

            D3dSurfaceMouseDown += OnD3dSurfaceMouseDown;
            D3dSurfaceMouseUp += OnD3dSurfaceMouseUp;

            // Add default mouse-move operations
            lock (MouseMoveOperations)
            {
                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.XyMove,
                                                LeftButtonState = MouseButtonState.Pressed,
                                                Modifiers = ModifierKeys.Shift
                                            });
                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.TargetZRotate,
                                                LeftButtonState = MouseButtonState.Pressed,
                                                Modifiers = ModifierKeys.Alt
                                            });
                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.CameraZRotate,
                                                LeftButtonState = MouseButtonState.Pressed,
                                                Modifiers = ModifierKeys.Alt | ModifierKeys.Control
                                            });

                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.ZMove,
                                                RightButtonState = MouseButtonState.Pressed,
                                                Modifiers = ModifierKeys.Shift
                                            });
                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.TargetXyRotate,
                                                RightButtonState = MouseButtonState.Pressed,
                                                Modifiers = ModifierKeys.Alt
                                            });
                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.CameraXyRotate,
                                                RightButtonState = MouseButtonState.Pressed,
                                                Modifiers = ModifierKeys.Alt | ModifierKeys.Control
                                            });

                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.Zoom,
                                                MiddleButtonState = MouseButtonState.Pressed
                                            });
                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.UniformZoom,
                                                MiddleButtonState = MouseButtonState.Pressed,
                                                Modifiers = ModifierKeys.Shift
                                            });

                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.ZoomToRegion,
                                                RightButtonState = MouseButtonState.Pressed,
                                                LeftButtonState = MouseButtonState.Pressed
                                            });
                MouseMoveOperations.Add(new MouseMoveOperation
                                            {
                                                Operation = CameraOperation.UniformZoomToRegion,
                                                RightButtonState = MouseButtonState.Pressed,
                                                LeftButtonState = MouseButtonState.Pressed,
                                                Modifiers = ModifierKeys.Shift
                                            });
            }           
        }

        void OnD3dSurfaceMouseDown(object sender, D3dSurfaceMouseButtonEventArgs e)
        {
            HandleZoomToRegion();
        }

        void OnD3dSurfaceMouseUp(object sender, D3dSurfaceMouseButtonEventArgs e)
        {
            HandleZoomToRegion();
        }

        private void OnD3dSurfaceMouseEnter(object sender, D3dSurfaceMouseEventArgs e)
        {
            _lastSurfaceMousePosition = e.D3dSurfaceMousePosition;

            // Pick the mouse-over shape, if needed.
            if (_isMouseOverShapeTestEnabled)
            {
                InvalidateCurrentMouseOverShape();
            }
        }

        private void OnD3dSurfaceMouseMove(object sender, D3dSurfaceMouseEventArgs e)
        {
            HandleZoomToRegion();

            List<CameraOperation> cameraOperations;

            lock (MouseMoveOperations)
            {
                cameraOperations =
                    MouseMoveOperations.Where(o => o.IsCurrentStateFitting()).Select(o => o.Operation).Distinct().ToList();
            }

            if (cameraOperations.Any())
            {
                Point currentSurfacePosition = e.D3dSurfaceMousePosition;
                Vector delta = currentSurfacePosition - _lastSurfaceMousePosition;
                float relativeDeltaX = (float)(delta.X / D3dSurfaceWidth);
                float relativeDeltaY = (float)(delta.Y / D3dSurfaceHeight);

                foreach (CameraOperation operation in cameraOperations)
                {
                    PerformOperation(operation, relativeDeltaX, relativeDeltaY);
                }

                if (_isInZoomToRegionMode && null != _regionIndicatorAdorner)
                {
                    _regionIndicatorAdorner.RectangleWidth += delta.X * (D3dRegionActualWidth / D3dSurfaceWidth);
                    _regionIndicatorAdorner.RectangleHeight += delta.Y * (D3dRegionActualHeight / D3dSurfaceHeight);
                    _regionIndicatorAdorner.InvalidateVisual();
                }
            }
            else
            {
                // Pick the mouse-over shape, if needed.
                if (_isMouseOverShapeTestEnabled)
                {
                    InvalidateCurrentMouseOverShape();
                }
            }

            _lastSurfaceMousePosition = e.D3dSurfaceMousePosition;
        }

        private void OnD3dSurfaceMouseLeave(object sender, D3dSurfaceMouseEventArgs e)
        {
            _lastSurfaceMousePosition = new Point(-1, -1);

            // Pick the mouse-over shape, if needed.
            if (_isMouseOverShapeTestEnabled)
            {
                InvalidateCurrentMouseOverShape();
            }
        }
        #endregion

        #region HandleZoomToRegion

        protected bool _isInZoomToRegionMode = false;

        protected void HandleZoomToRegion()
        {
            // Get the current ZoomToRegion operation state
            CameraOperation zoomToRegionOperation = CameraOperation.None;

            lock (MouseMoveOperations)
            {
                List<CameraOperation> cameraOperations =
                    MouseMoveOperations.Where(o => (CameraOperation.ZoomToRegion == o.Operation || CameraOperation.UniformZoomToRegion == o.Operation)
                        && o.IsCurrentStateFitting()).
                    Select(o => o.Operation).Distinct().ToList();

                if (cameraOperations.Any())
                {
                    zoomToRegionOperation = cameraOperations.First();
                }
            }

            if (CameraOperation.None == zoomToRegionOperation)
            {
                if (_isInZoomToRegionMode)
                {
                    // The region's selection operation has just ended...
                    ApplyZoomToRegion();
                }
            }
            else
            {
                // We are in ZoomToRegion state...

                if (!_isInZoomToRegionMode)
                {
                    // The region's selection operation has just started...
                    StartZoomToRegion();
                }
                else
                {
                    // We are in a middle of a region's selection operation...

                    if (null != _regionIndicatorAdorner)
                    {
                        _regionIndicatorAdorner.KeepAspectRatio = CameraOperation.UniformZoomToRegion ==
                                                                zoomToRegionOperation;
                    }
                }
            }
        }

        private void StartZoomToRegion()
        {
            if (null == _regionIndicatorAdorner)
            {
                return;
            }

            _regionIndicatorAdorner.RectangleTop = _lastSurfaceMousePosition.Y *
                                                  (D3dRegionActualHeight / D3dSurfaceHeight);
            _regionIndicatorAdorner.RectangleLeft = _lastSurfaceMousePosition.X *
                                                   (D3dRegionActualWidth / D3dSurfaceWidth);
            _regionIndicatorAdorner.RectangleWidth = 0;
            _regionIndicatorAdorner.RectangleHeight = 0;

            _regionIndicatorAdorner.Visibility = Visibility.Visible;
            _regionIndicatorAdorner.InvalidateVisual();

            _isInZoomToRegionMode = true;
        }

        private void ApplyZoomToRegion()
        {
            if (null == _regionIndicatorAdorner)
            {
                return;
            }

            if (Math.Abs(_regionIndicatorAdorner.ActualRectangleHeight) > 0 &&
                Math.Abs(_regionIndicatorAdorner.ActualRectangleWidth) > 0)
            {
                float selectedRegionLeft =
                    (float) (_regionIndicatorAdorner.ActualRectangleLeft/(D3dRegionActualWidth/2) - 1);
                float selectedRegionTop =
                    (float) (1 - _regionIndicatorAdorner.ActualRectangleTop/(D3dRegionActualHeight/2));
                float selectedRegionRight =
                    (float) (selectedRegionLeft + _regionIndicatorAdorner.Width/(D3dRegionActualWidth/2));
                float selectedRegionBottom =
                    (float) (selectedRegionTop - _regionIndicatorAdorner.Height/(D3dRegionActualHeight/2));

                PerformSceneAction(() => CurrentScene.Camera.ZoomToProjectionRegion(
                    selectedRegionLeft, selectedRegionTop, selectedRegionRight,
                    selectedRegionBottom, false));
            }

            _regionIndicatorAdorner.Visibility = Visibility.Collapsed;
            _regionIndicatorAdorner.InvalidateVisual();

            _isInZoomToRegionMode = false;
        }

        #endregion

        #region PerformOperation
        protected List<Action> _pendingActions = new List<Action>();

        private void PerformOperation(CameraOperation operation, float relativeDeltaX, float relativeDeltaY)
        {
            switch (operation)
            {
                case CameraOperation.Zoom:
                    PerformSceneAction(() => PerformZoom(relativeDeltaX, relativeDeltaY));
                    break;
                case CameraOperation.UniformZoom:
                    PerformSceneAction(() => PerformUniformZoom(relativeDeltaX, relativeDeltaY));
                    break;
                case CameraOperation.XyMove:
                    PerformSceneAction(() => PerformXyMove(relativeDeltaX, relativeDeltaY));
                    break;
                case CameraOperation.ZMove:
                    PerformSceneAction(() => PerformZMove(relativeDeltaX, relativeDeltaY));
                    break;
                case CameraOperation.TargetXyRotate:
                    PerformSceneAction(() => PerformTargetXyRotate(relativeDeltaX, relativeDeltaY));
                    break;
                case CameraOperation.TargetZRotate:
                    AdjustZRotateDelta(ref relativeDeltaX, ref relativeDeltaY);
                    PerformSceneAction(() => PerformTargetZRotate(relativeDeltaX, relativeDeltaY));
                    break;
                case CameraOperation.CameraXyRotate:
                    PerformSceneAction(() => PerformCameraXyRotate(relativeDeltaX, relativeDeltaY));
                    break;
                case CameraOperation.CameraZRotate:
                    AdjustZRotateDelta(ref relativeDeltaX, ref relativeDeltaY);
                    PerformSceneAction(() => PerformCameraZRotate(relativeDeltaX, relativeDeltaY));
                    break;
                case CameraOperation.ZoomToRegion:
                case CameraOperation.UniformZoomToRegion:
                    HandleZoomToRegion();
                    break;
            }
        }

        public void PerformSceneAction(Action a)
        {
            AddPendingAction(a);
            InvalidateScene();
        }

        public void AddPendingAction(Action a)
        {
            if (null == a)
            {
                return;
            }

            lock (_pendingActions)
            {
                _pendingActions.Add(a);
            }
        }

        protected void PerformXyMove(float relativeDeltaX, float relativeDeltaY)
        {
            CurrentScene.Camera.RelativeXyMove(-relativeDeltaX * 2, relativeDeltaY * 2);
        }

        protected void PerformZMove(float relativeDeltaX, float relativeDeltaY)
        {
            float relativeDeltaZ = Math.Abs(relativeDeltaX) > Math.Abs(relativeDeltaY)
                              ? relativeDeltaX
                              : -relativeDeltaY;

            CurrentScene.Camera.RelativeZMove(relativeDeltaZ);
        }

        protected void PerformZoom(float relativeDeltaX, float relativeDeltaY)
        {
            CurrentScene.Camera.Zoom(1 - relativeDeltaX, 1 + relativeDeltaY);
        }

        protected void PerformUniformZoom(float relativeDeltaX, float relativeDeltaY)
        {
            float relativeZoomDelta = Math.Abs(relativeDeltaX) > Math.Abs(relativeDeltaY)
                                          ? relativeDeltaX
                                          : -relativeDeltaY;

            PerformZoom(relativeZoomDelta, -relativeZoomDelta);
        }

        protected void PerformTargetZRotate(float relativeDeltaX, float relativeDeltaY)
        {            
            float relativeArcLength = relativeDeltaX + relativeDeltaY;
            CurrentScene.Camera.RelativeRotateZ(relativeArcLength, CameraTransformationCenterPosition.CameraPosition, CameraRotationDirection.Clockwise);
        }

        protected void PerformTargetXyRotate(float relativeDeltaX, float relativeDeltaY)
        {
            CurrentScene.Camera.RelativeRotateX(relativeDeltaY/8, CameraTransformationCenterPosition.CameraPosition, CameraRotationDirection.CounterClockwise);
            CurrentScene.Camera.RelativeRotateY(relativeDeltaX/8, CameraTransformationCenterPosition.CameraPosition, CameraRotationDirection.CounterClockwise);
        }

        protected void PerformCameraZRotate(float relativeDeltaX, float relativeDeltaY)
        {
            float relativeArcLength = relativeDeltaX + relativeDeltaY;
            CurrentScene.Camera.RelativeRotateZ(relativeArcLength, CameraTransformationCenterPosition.TargetPosition, CameraRotationDirection.Clockwise);
        }

        protected void PerformCameraXyRotate(float relativeDeltaX, float relativeDeltaY)
        {
            CurrentScene.Camera.RelativeRotateX(relativeDeltaY, CameraTransformationCenterPosition.TargetPosition, CameraRotationDirection.CounterClockwise);
            CurrentScene.Camera.RelativeRotateY(relativeDeltaX, CameraTransformationCenterPosition.TargetPosition, CameraRotationDirection.CounterClockwise);
        }

        private void AdjustZRotateDelta(ref float relativeDeltaX, ref float relativeDeltaY)
        {
            relativeDeltaX /= (D3dSurfaceHeight / 2) > _lastSurfaceMousePosition.Y ? 4 : -4;
            relativeDeltaY /= (D3dSurfaceWidth / 2) < _lastSurfaceMousePosition.X ? 4 : -4;
        }
        #endregion

        public void InvalidateScene()
        {
            if (null == CurrentScene)
            {
                return;
            }

            // Start the thread that renders the scene, if it is needed.
            if (_renderSceneThread == null)
            {
                StartRenderSceneThread();
            }

            // Indicate that the scene render is invalid.
            _renderSceneEvent.Set();
        }

        #region BeginSceneUpdate & EndSceneUpdate
        private readonly object _sceneUpdateLocker = new object();

        public void BeginSceneUpdate()
        {
            Monitor.Enter(_sceneUpdateLocker);
        }

        public void EndSceneUpdate()
        {
            Monitor.Exit(_sceneUpdateLocker);

            // Present the scene.
            InvalidateScene();
        }
        #endregion

        #region RenderScene
        private Thread _renderSceneThread = null;
        private bool _continueRenderSceneThread;
        private AutoResetEvent _renderSceneEvent = new AutoResetEvent(false);

        protected void RenderScene()
        {
            if (null == CurrentScene)
            {
                return;
            }
 
            List<Action> currentActions = new List<Action>();
            
            lock (_pendingActions)
            {
                currentActions.AddRange(_pendingActions);
                _pendingActions.Clear();
            }

            try
            {
                BeginDrawing();

                Monitor.Enter(_sceneUpdateLocker);

                // Perform scene actions.
                currentActions.ForEach(a => a());

                // Render the scene.
                CurrentScene.Render(D3dDevice);

                // Pick the mouse-over shape, if needed.
                if (_isMouseOverShapeTestEnabled)
                {
                    InvalidateCurrentMouseOverShape();
                }
            }
            catch
            {               
            }
            finally
            {
                Monitor.Exit(_sceneUpdateLocker);

                EndDrawing();
            }            
        }

        private void StartRenderSceneThread()
        {
            if (null == _renderSceneThread)
            {
                _continueRenderSceneThread = true;

                _renderSceneThread = new Thread(new ThreadStart(() =>
                {
                    while (_continueRenderSceneThread)
                    {
                        _renderSceneEvent.WaitOne();

                        if (_continueRenderSceneThread)
                        {
                            RenderScene();
                        }
                    }
                }));

                _renderSceneThread.Start();
            }
        }

        private void StopRenderSceneThread()
        {
            if (_renderSceneThread != null)
            {
                _continueRenderSceneThread = false;
                _renderSceneEvent.Set();
                _renderSceneThread.Join();
                _renderSceneThread = null;
            }
        }
        #endregion

        #region Pick
        private Thread _pickThread = null;
        private bool _continuePickThread;
        private AutoResetEvent _pickEvent = new AutoResetEvent(false);

        protected void UpdateCurrentMouseOverShape()
        {
            if (null == CurrentScene)
            {
                return;
            }

            Monitor.Enter(_sceneUpdateLocker);

            try
            {
                D3dShape currShape = (0 <= _lastSurfaceMousePosition.X && 0 <= _lastSurfaceMousePosition.Y)
                                         ? Pick(_lastSurfaceMousePosition.X, _lastSurfaceMousePosition.Y)
                                         : null;

                CurrentMouseOverShape = currShape;
            }
            catch
            {
            }
            finally
            {
                Monitor.Exit(_sceneUpdateLocker);
            }
        }

        private void StartPickThread()
        {
            if (null == _pickThread)
            {
                _continuePickThread = true;

                _pickThread = new Thread(new ThreadStart(() =>
                {
                    while (_continuePickThread)
                    {
                        _pickEvent.WaitOne();

                        if (_continuePickThread)
                        {
                            UpdateCurrentMouseOverShape();
                        }
                    }
                }));

                _pickThread.Start();
            }
        }

        private void StopPickThread()
        {
            if (_pickThread != null)
            {
                _continuePickThread = false;
                _pickEvent.Set();
                _pickThread.Join();
                _pickThread = null;
            }
        }

        public D3dShape Pick(double surfaceX, double surfaceY)
        {
            if (null == CurrentScene)
            {
                return null;
            }

            return CurrentScene.Pick(D3dDevice, (float) surfaceX, (float) surfaceY);
        }

        public void InvalidateCurrentMouseOverShape()
        {
            if (null == CurrentScene)
            {
                return;
            }

            // Start the thread that renders the scene, if it is needed.
            if (_pickThread == null)
            {
                StartPickThread();
            }

            // Indicate that the scene render is invalid.
            _pickEvent.Set();
        }
        #endregion

        #region Properties

        #region Scene
        public D3dScene Scene
        {
            get { return (D3dScene)GetValue(SceneProperty); }
            set { SetValue(SceneProperty, value); }
        }

        public static readonly DependencyProperty SceneProperty =
            DependencyProperty.Register("Scene", typeof(D3dScene), typeof(D3dScenePresenter),
            new UIPropertyMetadata(null, OnSceneChanged));

        private static void  OnSceneChanged(DependencyObject o, DependencyPropertyChangedEventArgs arg)
        {
            D3dScenePresenter dsp = o as D3dScenePresenter;
            if (null==dsp)
            {
                return;
            }

            // We can access a dependency-property only in the UI thread.
            // So, store the value in another property, for let accessing in other threads.
            dsp.CurrentScene = dsp.Scene;
        }

        protected D3dScene CurrentScene { get; private set; }
        #endregion

        #region MouseMoveOperations
        private List<MouseMoveOperation> _mouseMoveOperations;
        public List<MouseMoveOperation> MouseMoveOperations
        {
            get { return _mouseMoveOperations ?? (_mouseMoveOperations = new List<MouseMoveOperation>()); }
        }
        #endregion

        #region IsMouseOverShapeTestEnabled

        public bool IsMouseOverShapeTestEnabled
        {
            get { return (bool)GetValue(IsMouseOverShapeTestEnabledProperty); }
            set { SetValue(IsMouseOverShapeTestEnabledProperty, value); }
        }

        public static readonly DependencyProperty IsMouseOverShapeTestEnabledProperty =
            DependencyProperty.Register("IsMouseOverShapeTestEnabled", typeof(bool), typeof(D3dScenePresenter),
            new UIPropertyMetadata(false, OnIsMouseOverShapeTestEnabledChanged));

        private static void OnIsMouseOverShapeTestEnabledChanged(DependencyObject o, DependencyPropertyChangedEventArgs arg)
        {
            D3dScenePresenter dsp = o as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            // We can access a dependency-property only in the UI thread.
            // So, store the value in another property, for let accessing in other threads.
            dsp._isMouseOverShapeTestEnabled = dsp.IsMouseOverShapeTestEnabled;
        }

        private bool _isMouseOverShapeTestEnabled;

        #endregion

        #region CurrentMouseOverShape

        private D3dShape _currentMouseOverShape;
        public D3dShape CurrentMouseOverShape
        {
            get { return _currentMouseOverShape; }
            protected set
            {
                if (value != _currentMouseOverShape)
                {
                    D3dShape oldValue = _currentMouseOverShape;
                    _currentMouseOverShape = value;

                    // Raise MouseOverShapeChanged event
                    Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                           new ThreadStart(() =>
                                                               {
                                                                   MouseOverShapeChangedRoutedEventArgs arg =
                                                                       new MouseOverShapeChangedRoutedEventArgs(
                                                                           D3dScenePresenter.MouseOverShapeChangedEvent)
                                                                           {
                                                                               OldShape = oldValue,
                                                                               NewShape = _currentMouseOverShape
                                                                           };

                                                                   RaiseEvent(arg);
                                                               }));
                }
            }
        }

        #endregion

        #region RegionIndicatorFillBrush

        public Brush RegionIndicatorFillBrush
        {
            get { return (Brush)GetValue(RegionIndicatorFillBrushProperty); }
            set { SetValue(RegionIndicatorFillBrushProperty, value); }
        }

        public static readonly DependencyProperty RegionIndicatorFillBrushProperty =
            DependencyProperty.Register("RegionIndicatorFillBrush", typeof (Brush), typeof (D3dScenePresenter),
                                        new UIPropertyMetadata(new SolidColorBrush(new Color
                                                                                       {
                                                                                           A = 128,
                                                                                           R = 0,
                                                                                           G = 0,
                                                                                           B = 0
                                                                                       }), OnRegionIndicatorFillBrushChanged));

        private static void OnRegionIndicatorFillBrushChanged(DependencyObject o, DependencyPropertyChangedEventArgs arg)
        {
            D3dScenePresenter dsp = o as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            if (null != dsp._regionIndicatorAdorner)
            {
                dsp._regionIndicatorAdorner.FillBrush = dsp.RegionIndicatorFillBrush;
            }
        }
        
        #endregion

        #region RegionIndicatorBorderPen

        public Pen RegionIndicatorBorderPen
        {
            get { return (Pen)GetValue(RegionIndicatorBorderPenProperty); }
            set { SetValue(RegionIndicatorBorderPenProperty, value); }
        }

        public static readonly DependencyProperty RegionIndicatorBorderPenProperty =
            DependencyProperty.Register("RegionIndicatorBorderPen", typeof (Pen), typeof (D3dScenePresenter),
                                        new UIPropertyMetadata(new Pen(new SolidColorBrush(new Color
                                                                                               {
                                                                                                   A = 128,
                                                                                                   R = 255,
                                                                                                   G = 255,
                                                                                                   B = 255
                                                                                               }), 2)
                                                                   {
                                                                       DashStyle = new DashStyle(new double[] {5, 5}, 0)
                                                                   }, OnRegionIndicatorBorderPenChanged));

        private static void OnRegionIndicatorBorderPenChanged(DependencyObject o, DependencyPropertyChangedEventArgs arg)
        {
            D3dScenePresenter dsp = o as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            if (null != dsp._regionIndicatorAdorner)
            {
                dsp._regionIndicatorAdorner.BorderPen = dsp.RegionIndicatorBorderPen;
            }
        }
       
        #endregion

        #endregion

        #region Commands

        #region AdjustCameraViewCommand

        private static RoutedCommand _adjustCameraViewCommand;
        public static RoutedCommand AdjustCameraViewCommand
        {
            get
            {
                return _adjustCameraViewCommand ??
                       (_adjustCameraViewCommand =
                        new RoutedCommand("AdjustCameraView", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteAdjustCameraViewCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteAdjustCameraViewCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            dsp.AdjustCameraView();
        }

        protected void AdjustCameraView()
        {
            PerformSceneAction(() =>
                                   {
                                       if (null != CurrentScene)
                                       {
                                           CurrentScene.AdjustCameraView();
                                       }
                                   });
        }

        #endregion

        #region HorizontalZoomCommand

        private static RoutedCommand _horizontalZoomCommand;
        public static RoutedCommand HorizontalZoomCommand
        {
            get
            {
                return _horizontalZoomCommand ??
                       (_horizontalZoomCommand =
                        new RoutedCommand("HorizontalZoom", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteHorizontalZoomCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteHorizontalZoomCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float scalingFactor = 1;
            float.TryParse(e.Parameter.ToString(), out scalingFactor);
            dsp.HorizontalZoom(scalingFactor);
        }

        protected void HorizontalZoom(float scalingFactor)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.Zoom(scalingFactor, 1);
                }
            });
        }

        #endregion

        #region VerticalZoomCommand

        private static RoutedCommand _verticalZoomCommand;
        public static RoutedCommand VerticalZoomCommand
        {
            get
            {
                return _verticalZoomCommand ??
                       (_verticalZoomCommand =
                        new RoutedCommand("VerticalZoom", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteVerticalZoomCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteVerticalZoomCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float scalingFactor = 1;
            float.TryParse(e.Parameter.ToString(), out scalingFactor);
            dsp.VerticalZoom(scalingFactor);
        }

        protected void VerticalZoom(float scalingFactor)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.Zoom(1, scalingFactor);
                }
            });
        }

        #endregion

        #region UniformZoomCommand

        private static RoutedCommand _uniformZoomCommand;
        public static RoutedCommand UniformZoomCommand
        {
            get
            {
                return _uniformZoomCommand ??
                       (_uniformZoomCommand =
                        new RoutedCommand("UniformZoom", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteUniformZoomCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteUniformZoomCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float scalingFactor = 1;
            float.TryParse(e.Parameter.ToString(), out scalingFactor);
            dsp.UniformZoom(scalingFactor);
        }

        protected void UniformZoom(float scalingFactor)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.Zoom(scalingFactor, scalingFactor);
                }
            });
        }

        #endregion

        #region HorizontalMoveCommand

        private static RoutedCommand _horizontalMoveCommand;
        public static RoutedCommand HorizontalMoveCommand
        {
            get
            {
                return _horizontalMoveCommand ??
                       (_horizontalMoveCommand =
                        new RoutedCommand("HorizontalMove", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteHorizontalMoveCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteHorizontalMoveCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float relativeDelta = 0;
            float.TryParse(e.Parameter.ToString(), out relativeDelta);
            dsp.HorizontalMove(relativeDelta);
        }

        protected void HorizontalMove(float relativeDelta)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeXyMove(relativeDelta, 0);
                }
            });
        }

        #endregion

        #region VerticalMoveCommand

        private static RoutedCommand _verticalMoveCommand;
        public static RoutedCommand VerticalMoveCommand
        {
            get
            {
                return _verticalMoveCommand ??
                       (_verticalMoveCommand =
                        new RoutedCommand("VerticalMove", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteVerticalMoveCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteVerticalMoveCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float relativeDelta = 0;
            float.TryParse(e.Parameter.ToString(), out relativeDelta);
            dsp.VerticalMove(relativeDelta);
        }

        protected void VerticalMove(float relativeDelta)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeXyMove(0, relativeDelta);
                }
            });
        }

        #endregion

        #region MoveAtLookDirectionCommand

        private static RoutedCommand _moveAtLookDirectionCommand;
        public static RoutedCommand MoveAtLookDirectionCommand
        {
            get
            {
                return _moveAtLookDirectionCommand ??
                       (_moveAtLookDirectionCommand =
                        new RoutedCommand("MoveAtLookDirection", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteMoveAtLookDirectionCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteMoveAtLookDirectionCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float relativeDelta = 0;
            float.TryParse(e.Parameter.ToString(), out relativeDelta);
            dsp.MoveAtLookDirection(relativeDelta);
        }

        protected void MoveAtLookDirection(float relativeDelta)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeZMove(relativeDelta);
                }
            });
        }

        #endregion

        #region RotateCameraAroundXAxisCommand

        private static RoutedCommand _rotateCameraAroundXAxisCommand;
        public static RoutedCommand RotateCameraAroundXAxisCommand
        {
            get
            {
                return _rotateCameraAroundXAxisCommand ??
                       (_rotateCameraAroundXAxisCommand =
                        new RoutedCommand("RotateCameraAroundXAxis", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteRotateCameraAroundXAxisCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteRotateCameraAroundXAxisCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float radians = 0;
            float.TryParse(e.Parameter.ToString(), out radians);
            dsp.RotateCameraAroundXAxis(radians);
        }

        protected void RotateCameraAroundXAxis(float radians)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeRotateX(radians, CameraTransformationCenterPosition.TargetPosition,
                                                        CameraRotationDirection.Clockwise);
                }
            });
        }

        #endregion

        #region RotateCameraAroundYAxisCommand

        private static RoutedCommand _rotateCameraAroundYAxisCommand;
        public static RoutedCommand RotateCameraAroundYAxisCommand
        {
            get
            {
                return _rotateCameraAroundYAxisCommand ??
                       (_rotateCameraAroundYAxisCommand =
                        new RoutedCommand("RotateCameraAroundYAxis", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteRotateCameraAroundYAxisCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteRotateCameraAroundYAxisCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float radians = 0;
            float.TryParse(e.Parameter.ToString(), out radians);
            dsp.RotateCameraAroundYAxis(radians);
        }

        protected void RotateCameraAroundYAxis(float radians)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeRotateY(radians, CameraTransformationCenterPosition.TargetPosition,
                                                        CameraRotationDirection.Clockwise);
                }
            });
        }

        #endregion

        #region RotateCameraAroundZAxisCommand

        private static RoutedCommand _rotateCameraAroundZAxisCommand;
        public static RoutedCommand RotateCameraAroundZAxisCommand
        {
            get
            {
                return _rotateCameraAroundZAxisCommand ??
                       (_rotateCameraAroundZAxisCommand =
                        new RoutedCommand("RotateCameraAroundZAxis", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteRotateCameraAroundZAxisCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteRotateCameraAroundZAxisCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float radians = 0;
            float.TryParse(e.Parameter.ToString(), out radians);
            dsp.RotateCameraAroundZAxis(radians);
        }

        protected void RotateCameraAroundZAxis(float radians)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeRotateZ(radians, CameraTransformationCenterPosition.TargetPosition,
                                                        CameraRotationDirection.Clockwise);
                }
            });
        }

        #endregion

        #region RotateTargetAroundXAxisCommand

        private static RoutedCommand _rotateTargetAroundXAxisCommand;
        public static RoutedCommand RotateTargetAroundXAxisCommand
        {
            get
            {
                return _rotateTargetAroundXAxisCommand ??
                       (_rotateTargetAroundXAxisCommand =
                        new RoutedCommand("RotateTargetAroundXAxis", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteRotateTargetAroundXAxisCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteRotateTargetAroundXAxisCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float radians = 0;
            float.TryParse(e.Parameter.ToString(), out radians);
            dsp.RotateTargetAroundXAxis(radians);
        }

        protected void RotateTargetAroundXAxis(float radians)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeRotateX(radians, CameraTransformationCenterPosition.CameraPosition,
                                                        CameraRotationDirection.Clockwise);
                }
            });
        }

        #endregion

        #region RotateTargetAroundYAxisCommand

        private static RoutedCommand _rotateTargetAroundYAxisCommand;
        public static RoutedCommand RotateTargetAroundYAxisCommand
        {
            get
            {
                return _rotateTargetAroundYAxisCommand ??
                       (_rotateTargetAroundYAxisCommand =
                        new RoutedCommand("RotateTargetAroundYAxis", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteRotateTargetAroundYAxisCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteRotateTargetAroundYAxisCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float radians = 0;
            float.TryParse(e.Parameter.ToString(), out radians);
            dsp.RotateTargetAroundYAxis(radians);
        }

        protected void RotateTargetAroundYAxis(float radians)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeRotateY(radians, CameraTransformationCenterPosition.CameraPosition,
                                                        CameraRotationDirection.Clockwise);
                }
            });
        }

        #endregion

        #region RotateTargetAroundZAxisCommand

        private static RoutedCommand _rotateTargetAroundZAxisCommand;
        public static RoutedCommand RotateTargetAroundZAxisCommand
        {
            get
            {
                return _rotateTargetAroundZAxisCommand ??
                       (_rotateTargetAroundZAxisCommand =
                        new RoutedCommand("RotateTargetAroundZAxis", typeof(D3dScenePresenter)));
            }
        }

        protected static void CanExecuteRotateTargetAroundZAxisCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            e.CanExecute = true;
        }

        protected static void ExecuteRotateTargetAroundZAxisCommand(object sender, ExecutedRoutedEventArgs e)
        {
            D3dScenePresenter dsp = sender as D3dScenePresenter;
            if (null == dsp)
            {
                return;
            }

            float radians = 0;
            float.TryParse(e.Parameter.ToString(), out radians);
            dsp.RotateTargetAroundZAxis(radians);
        }

        protected void RotateTargetAroundZAxis(float radians)
        {
            PerformSceneAction(() =>
            {
                if (null != CurrentScene)
                {
                    CurrentScene.Camera.RelativeRotateZ(radians, CameraTransformationCenterPosition.CameraPosition,
                                                        CameraRotationDirection.Clockwise);
                }
            });
        }

        #endregion

        #endregion

        #region Events

        #region MouseOverShapeChanged

        public static readonly RoutedEvent MouseOverShapeChangedEvent = EventManager.RegisterRoutedEvent(
            "MouseOverShapeChanged", RoutingStrategy.Bubble, typeof (MouseOverShapeChangedRoutedEventHandler),
            typeof (D3dScenePresenter));

        public event MouseOverShapeChangedRoutedEventHandler MouseOverShapeChanged
        {
            add { AddHandler(MouseOverShapeChangedEvent, value); }
            remove { RemoveHandler(MouseOverShapeChangedEvent, value); }
        }

        #endregion

        #endregion

        #region IDisposable implementation
        public override void Dispose()
        {
            StopRenderSceneThread();
            StopPickThread();

            base.Dispose();
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions