private void TrackUIPointer(ref Ray r, RenderUIElement root, bool nonui)
        {
            if (root.Component.AlwaysTrackPointer == false)
            {
                return;
            }

            UIElement rootElement = root.Page.RootElement;

            if (rootElement.Intersects(ref r, out var intersectionPoint, nonui, root.Component.TrackedCanvasScale))
            {
                Vector2 pos;

                if (nonui)
                {
                    root.WorldMatrix3D.Decompose(out Vector3 scale, out Matrix rotation, out Vector3 translation);
                    Vector3 pos3d = intersectionPoint - translation;
                    rotation.Invert();
                    pos   = Vector3.Transform(pos3d, rotation).XY() / scale.XY();
                    pos.Y = root.Resolution.Y * 0.5f - pos.Y;
                }
                else
                {
                    pos    = intersectionPoint.XY();
                    pos.Y += root.Resolution.Y * 0.5f;
                }
                pos.X += root.Resolution.X * 0.5f;
                pos.X -= rootElement.RenderOffsets.X;
                pos.Y -= rootElement.RenderOffsets.Y;

                root.Component.AveragePositionIndex = (root.Component.AveragePositionIndex + 1) % root.Component.AveragedPositions.Length;
                root.Component.AveragedPositions[root.Component.AveragePositionIndex] = pos;
            }
 private void copyLastUiComponentAverage(RenderUIElement root)
 {
     if ((root.Component.AveragedPositions?.Length ?? 0) > 1)
     {
         // copy last entry
         Vector2 lastEntry = root.Component.AveragedPositions[root.Component.AveragePositionIndex];
         root.Component.AveragePositionIndex = (root.Component.AveragePositionIndex + 1) % root.Component.AveragedPositions.Length;
         root.Component.AveragedPositions[root.Component.AveragePositionIndex] = lastEntry;
     }
 }
            public void Update(RenderUIElement renderObject, Vector3 virtualResolution)
            {
                var nearPlane   = virtualResolution.Z / 2;
                var farPlane    = nearPlane + virtualResolution.Z;
                var zOffset     = nearPlane + virtualResolution.Z / 2;
                var aspectRatio = virtualResolution.X / virtualResolution.Y;
                var verticalFov = (float)Math.Atan2(virtualResolution.Y / 2, zOffset) * 2;

                Matrix vm = Matrix.LookAtRH(new Vector3(0, 0, zOffset), Vector3.Zero, Vector3.UnitY);
                Matrix pm = Matrix.PerspectiveFovRH(verticalFov, aspectRatio, nearPlane, farPlane);

                Update(renderObject, MathUtil.RadiansToDegrees(verticalFov), ref vm, ref pm);
            }
        partial void PickingUpdate(RenderUIElement renderUIElement, Viewport viewport, ref Matrix worldViewProj, GameTime drawTime)
        {
            if (renderUIElement.Page?.RootElement == null)
            {
                return;
            }

            var inverseZViewProj = worldViewProj;

            inverseZViewProj.Row3 = -inverseZViewProj.Row3;

            UpdateMouseOver(ref viewport, ref inverseZViewProj, renderUIElement);
            UpdateTouchEvents(ref viewport, ref inverseZViewProj, renderUIElement, drawTime);
        }
Exemple #5
0
            public void Update(RenderUIElement renderObject, Vector3 virtualResolution)
            {
                var nearPlane   = virtualResolution.Z / 2;
                var farPlane    = nearPlane + virtualResolution.Z;
                var zOffset     = nearPlane + virtualResolution.Z / 2;
                var aspectRatio = virtualResolution.X / virtualResolution.Y;
                var verticalFov = (float)Math.Atan2(virtualResolution.Y / 2, zOffset) * 2;

                var cameraComponent = new CameraComponent(nearPlane, farPlane)
                {
                    UseCustomAspectRatio = true,
                    AspectRatio          = aspectRatio,
                    VerticalFieldOfView  = MathUtil.RadiansToDegrees(verticalFov),
                    ViewMatrix           = Matrix.LookAtRH(new Vector3(0, 0, zOffset), Vector3.Zero, Vector3.UnitY),
                    ProjectionMatrix     = Matrix.PerspectiveFovRH(verticalFov, aspectRatio, nearPlane, farPlane),
                };

                Update(renderObject, cameraComponent);
            }
        private void UpdateMouseOver(ref Viewport viewport, ref Matrix worldViewProj, RenderUIElement state)
        {
            if (input == null || !input.HasMouse)
            {
                return;
            }

            var intersectionPoint    = Vector3.Zero;
            var mousePosition        = input.MousePosition;
            var rootElement          = state.Page.RootElement;
            var lastMouseOverElement = state.LastMouseOverElement;

            // determine currently overred element.
            if (mousePosition != state.LastMousePosition)
            {
                Ray uiRay;
                if (!GetTouchPosition(state.Resolution, ref viewport, ref worldViewProj, mousePosition, out uiRay))
                {
                    return;
                }

                UIElementUnderMouseCursor = GetElementAtScreenPosition(rootElement, ref uiRay, ref worldViewProj, ref intersectionPoint);
            }

            // find the common parent between current and last overred elements
            var commonElement = FindCommonParent(UIElementUnderMouseCursor, lastMouseOverElement);

            // disable mouse over state to previously overred hierarchy
            var parent = lastMouseOverElement;

            while (parent != commonElement && parent != null)
            {
                parent.MouseOverState = MouseOverState.MouseOverNone;
                parent = parent.VisualParent;
            }

            // enable mouse over state to currently overred hierarchy
            if (UIElementUnderMouseCursor != null)
            {
                // the element itself
                UIElementUnderMouseCursor.MouseOverState = MouseOverState.MouseOverElement;

                // its hierarchy
                parent = UIElementUnderMouseCursor.VisualParent;
                while (parent != null)
                {
                    if (parent.IsHierarchyEnabled)
                    {
                        parent.MouseOverState = MouseOverState.MouseOverChild;
                    }

                    parent = parent.VisualParent;
                }
            }

            // update cached values
            state.LastMouseOverElement = UIElementUnderMouseCursor;
            state.LastMousePosition    = mousePosition;
        }
        private void UpdateTouchEvents(ref Viewport viewport, ref Matrix worldViewProj, RenderUIElement state, GameTime gameTime)
        {
            var rootElement       = state.Page.RootElement;
            var intersectionPoint = Vector3.Zero;
            var lastTouchPosition = new Vector2(float.NegativeInfinity);

            // analyze pointer event input and trigger UI touch events depending on hit Tests
            foreach (var pointerEvent in compactedPointerEvents)
            {
                // performance optimization: skip all the events that started outside of the UI
                var lastTouchedElement = state.LastTouchedElement;
                if (lastTouchedElement == null && pointerEvent.EventType != PointerEventType.Pressed)
                {
                    continue;
                }

                var time = gameTime.Total;

                var currentTouchPosition  = pointerEvent.Position;
                var currentTouchedElement = lastTouchedElement;

                // re-calculate the element under cursor if click position changed.
                if (lastTouchPosition != currentTouchPosition)
                {
                    Ray uiRay;
                    if (!GetTouchPosition(state.Resolution, ref viewport, ref worldViewProj, currentTouchPosition, out uiRay))
                    {
                        continue;
                    }

                    currentTouchedElement = GetElementAtScreenPosition(rootElement, ref uiRay, ref worldViewProj, ref intersectionPoint);
                }

                if (pointerEvent.EventType == PointerEventType.Pressed || pointerEvent.EventType == PointerEventType.Released)
                {
                    state.LastIntersectionPoint = intersectionPoint;
                }

                // TODO: add the pointer type to the event args?
                var touchEvent = new TouchEventArgs
                {
                    Action            = TouchAction.Down,
                    Timestamp         = time,
                    ScreenPosition    = currentTouchPosition,
                    ScreenTranslation = pointerEvent.DeltaPosition,
                    WorldPosition     = intersectionPoint,
                    WorldTranslation  = intersectionPoint - state.LastIntersectionPoint
                };

                switch (pointerEvent.EventType)
                {
                case PointerEventType.Pressed:
                    touchEvent.Action = TouchAction.Down;
                    currentTouchedElement?.RaiseTouchDownEvent(touchEvent);
                    break;

                case PointerEventType.Released:
                    touchEvent.Action = TouchAction.Up;

                    // generate enter/leave events if we passed from an element to another without move events
                    if (currentTouchedElement != lastTouchedElement)
                    {
                        ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent);
                    }

                    // trigger the up event
                    currentTouchedElement?.RaiseTouchUpEvent(touchEvent);
                    break;

                case PointerEventType.Moved:
                    touchEvent.Action = TouchAction.Move;

                    // first notify the move event (even if the touched element changed in between it is still coherent in one of its parents)
                    currentTouchedElement?.RaiseTouchMoveEvent(touchEvent);

                    // then generate enter/leave events if we passed from an element to another
                    if (currentTouchedElement != lastTouchedElement)
                    {
                        ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent);
                    }
                    break;

                case PointerEventType.Canceled:
                    touchEvent.Action = TouchAction.Move;

                    // generate enter/leave events if we passed from an element to another without move events
                    if (currentTouchedElement != lastTouchedElement)
                    {
                        ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent);
                    }

                    // then raise leave event to all the hierarchy of the previously selected element.
                    var element = currentTouchedElement;
                    while (element != null)
                    {
                        if (element.IsTouched)
                        {
                            element.RaiseTouchLeaveEvent(touchEvent);
                        }
                        element = element.VisualParent;
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                lastTouchPosition           = currentTouchPosition;
                state.LastTouchedElement    = currentTouchedElement;
                state.LastIntersectionPoint = intersectionPoint;
            }
        }
Exemple #8
0
 partial void PickingUpdate(RenderUIElement renderUIElement, Viewport viewport, ref Matrix worldViewProj, GameTime drawTime);
Exemple #9
0
 public UIElementState(RenderUIElement renderObject)
 {
     RenderObject = renderObject;
     WorldViewProjectionMatrix = Matrix.Identity;
 }
Exemple #10
0
 partial void PickingUpdate(RenderUIElement renderUIElement, Viewport viewport, ref Matrix worldViewProj, GameTime drawTime, List <PointerEvent> compactedPointerEvents);
Exemple #11
0
            public void Update(RenderUIElement renderObject, float vFoV, ref Matrix viewMatrix, ref Matrix projMatrix)
            {
                var worldMatrix = renderObject.WorldMatrix;

                // rotate the UI element perpendicular to the camera view vector, if billboard is activated
                if (renderObject.IsFullScreen)
                {
                    Matrix.Scaling(ref renderObject.Component.Entity.Transform.Scale, out Matrix scalar);
                    worldMatrix = ReallyCloseUI * scalar;
                }
                else
                {
                    if (renderObject.IsBillboard || renderObject.IsFullScreen)
                    {
                        Matrix viewInverse;
                        Matrix.Invert(ref viewMatrix, out viewInverse);
                        var diff = worldMatrix.TranslationVector - viewInverse.TranslationVector;

                        if (renderObject.IsBillboard)
                        {
                            switch (renderObject.Component.BillboardType)
                            {
                            case UIComponent.BILLBOARD_TYPE.VIEW:
                                var viewInverseRow1 = viewInverse.Row1;
                                var viewInverseRow2 = viewInverse.Row2;

                                // remove scale of the camera
                                viewInverseRow1 /= viewInverseRow1.XYZ().Length();
                                viewInverseRow2 /= viewInverseRow2.XYZ().Length();

                                // set the scale of the object
                                viewInverseRow1 *= worldMatrix.Row1.XYZ().Length();
                                viewInverseRow2 *= worldMatrix.Row2.XYZ().Length();

                                // set the adjusted world matrix
                                worldMatrix.Row1 = viewInverseRow1;
                                worldMatrix.Row2 = viewInverseRow2;
                                worldMatrix.Row3 = viewInverse.Row3;
                                break;

                            case UIComponent.BILLBOARD_TYPE.POSITION:
                                // generate a new matrix that looks at the camera's position
                                Quaternion look = new Quaternion();
                                Quaternion.LookAt(ref look, diff);
                                TransformComponent original = renderObject.Component.Entity.Transform;
                                worldMatrix = Matrix.Transformation(original.WorldScale(), look, original.WorldPosition());
                                break;
                            }
                        }

                        if (renderObject.IsFixedSize)
                        {
                            var distVec = diff.Length();

                            worldMatrix.Row1 *= distVec;
                            worldMatrix.Row2 *= distVec;
                            worldMatrix.Row3 *= distVec;
                        }
                    }

                    // If the UI component is not drawn fullscreen it should be drawn as a quad with world sizes corresponding to its actual size
                    worldMatrix = Matrix.Scaling(1f / renderObject.Resolution) * worldMatrix;
                }

                // capture 3D world matrix for picking against things in 3D space
                renderObject.WorldMatrix3D = worldMatrix;

                // Rotation of Pi along 0x to go from UI space to world space
                worldMatrix.Row2 = -worldMatrix.Row2;
                worldMatrix.Row3 = -worldMatrix.Row3;

                Matrix worldViewMatrix;

                Matrix.Multiply(ref worldMatrix, ref viewMatrix, out worldViewMatrix);
                Matrix.Multiply(ref worldViewMatrix, ref projMatrix, out WorldViewProjectionMatrix);
            }
        private bool UpdateMouseOver(ref Viewport viewport, ref Matrix worldViewProj, RenderUIElement state, GameTime time)
        {
            bool VRcontrollerUsed = VirtualReality.VRDeviceSystem.VRActive && (TransformComponent.LastLeftHandTracked != null || TransformComponent.LastRightHandTracked != null);

            if (input == null || !input.HasMouse && VRcontrollerUsed == false)
            {
                return(false);
            }

            var intersectionPoint    = Vector3.Zero;
            var rootElement          = state.Page.RootElement;
            var lastMouseOverElement = state.LastMouseOverElement;

            UIElementUnderMouseCursor = lastMouseOverElement;

            if (VRcontrollerUsed)
            {
                for (int i = 0; i < 2; i++)
                {
                    TransformComponent useHand = i == 0 ? (TransformComponent.OverrideRightHandUIPointer ?? TransformComponent.LastRightHandTracked) :
                                                 (TransformComponent.OverrideLeftHandUIPointer ?? TransformComponent.LastLeftHandTracked);

                    if (useHand != null)
                    {
                        Ray uiRay = new Ray(useHand.WorldPosition(), useHand.Forward(true));

                        UIElementVivePointed = UIElementUnderMouseCursor = GetElementAtWorldPosition(rootElement, ref uiRay, ref worldViewProj, ref intersectionPoint);

                        if (UIElementUnderMouseCursor != null)
                        {
                            // wait, are we selecting this element?
                            VirtualReality.TouchController tc = VirtualReality.VRDeviceSystem.GetSystem.GetController(i == 0 ? VirtualReality.TouchControllerHand.Right : VirtualReality.TouchControllerHand.Left);

                            if (tc != null)
                            {
                                if (tc.IsPressedDown(VirtualReality.VRDeviceSystem.UIActivationButton))
                                {
                                    MakeTouchEvent(UIElementUnderMouseCursor, lastMouseOverElement, PointerEventType.Pressed, Vector2.Zero, Vector2.Zero, intersectionPoint, intersectionPoint - state.LastIntersectionPoint, time);
                                }
                                else if (tc.IsPressReleased(VirtualReality.VRDeviceSystem.UIActivationButton))
                                {
                                    MakeTouchEvent(UIElementUnderMouseCursor, lastMouseOverElement, PointerEventType.Released, Vector2.Zero, Vector2.Zero, intersectionPoint, intersectionPoint - state.LastIntersectionPoint, time);
                                }
                            }

                            break;
                        }
                    }
                }
            }
            else
            {
                var mousePosition = input.MousePosition;

                // determine currently overred element.
                if (mousePosition != state.LastMousePosition)
                {
                    state.LastMousePosition = mousePosition;

                    Ray uiRay;
                    if (!GetTouchPosition(state.Resolution, ref viewport, ref worldViewProj, mousePosition, out uiRay))
                    {
                        return(true);
                    }

                    UIElementUnderMouseCursor = GetElementAtScreenPosition(rootElement, ref uiRay, ref worldViewProj, ref intersectionPoint);
                }
            }

            // find the common parent between current and last overred elements
            var commonElement = FindCommonParent(UIElementUnderMouseCursor, lastMouseOverElement);

            // disable mouse over state to previously overred hierarchy
            var parent = lastMouseOverElement;

            while (parent != commonElement && parent != null)
            {
                parent.MouseOverState = MouseOverState.MouseOverNone;
                parent = parent.VisualParent;
            }

            // enable mouse over state to currently overred hierarchy
            if (UIElementUnderMouseCursor != null)
            {
                // the element itself
                UIElementUnderMouseCursor.MouseOverState = MouseOverState.MouseOverElement;

                // its hierarchy
                parent = UIElementUnderMouseCursor.VisualParent;
                while (parent != null)
                {
                    if (parent.IsHierarchyEnabled)
                    {
                        parent.MouseOverState = MouseOverState.MouseOverChild;
                    }

                    parent = parent.VisualParent;
                }
            }

            // update cached values
            state.LastMouseOverElement = UIElementUnderMouseCursor;

            return(!VRcontrollerUsed);
        }
        private void UpdateTouchEvents(ref Viewport viewport, ref Matrix worldViewProj, RenderUIElement state, GameTime gameTime)
        {
            var rootElement       = state.Page.RootElement;
            var intersectionPoint = Vector3.Zero;
            var lastTouchPosition = new Vector2(float.NegativeInfinity);

            // analyze pointer event input and trigger UI touch events depending on hit Tests
            foreach (var pointerEvent in compactedPointerEvents)
            {
                // performance optimization: skip all the events that started outside of the UI
                var lastTouchedElement = state.LastTouchedElement;
                if (lastTouchedElement == null && pointerEvent.EventType != PointerEventType.Pressed)
                {
                    continue;
                }

                var currentTouchPosition  = pointerEvent.Position;
                var currentTouchedElement = lastTouchedElement;

                // re-calculate the element under cursor if click position changed.
                if (lastTouchPosition != currentTouchPosition)
                {
                    Ray uiRay;
                    if (!GetTouchPosition(state.Resolution, ref viewport, ref worldViewProj, currentTouchPosition, out uiRay))
                    {
                        continue;
                    }

                    currentTouchedElement = GetElementAtScreenPosition(rootElement, ref uiRay, ref worldViewProj, ref intersectionPoint);
                }

                if (pointerEvent.EventType == PointerEventType.Pressed || pointerEvent.EventType == PointerEventType.Released)
                {
                    state.LastIntersectionPoint = intersectionPoint;
                }

                MakeTouchEvent(currentTouchedElement, lastTouchedElement, pointerEvent.EventType, currentTouchPosition, pointerEvent.DeltaPosition, intersectionPoint,
                               intersectionPoint - state.LastIntersectionPoint, gameTime);

                lastTouchPosition           = currentTouchPosition;
                state.LastTouchedElement    = currentTouchedElement;
                state.LastIntersectionPoint = intersectionPoint;
            }
        }
Exemple #14
0
            public void Update(RenderUIElement renderObject, CameraComponent camera)
            {
                var frustumHeight = 2 * (float)Math.Tan(MathUtil.DegreesToRadians(camera.VerticalFieldOfView) / 2);

                var worldMatrix = renderObject.WorldMatrix;

                // rotate the UI element perpendicular to the camera view vector, if billboard is activated
                if (renderObject.IsFullScreen)
                {
                    worldMatrix = Matrix.Identity;
                }
                else
                {
                    Matrix viewInverse;
                    Matrix.Invert(ref camera.ViewMatrix, out viewInverse);
                    var forwardVector = viewInverse.Forward;

                    if (renderObject.IsBillboard)
                    {
                        // remove scale of the camera
                        viewInverse.Row1 /= viewInverse.Row1.XYZ().Length();
                        viewInverse.Row2 /= viewInverse.Row2.XYZ().Length();

                        // set the scale of the object
                        viewInverse.Row1 *= worldMatrix.Row1.XYZ().Length();
                        viewInverse.Row2 *= worldMatrix.Row2.XYZ().Length();

                        // set the adjusted world matrix
                        worldMatrix.Row1 = viewInverse.Row1;
                        worldMatrix.Row2 = viewInverse.Row2;
                        worldMatrix.Row3 = viewInverse.Row3;
                    }

                    if (renderObject.IsFixedSize)
                    {
                        forwardVector.Normalize();
                        var   distVec = (worldMatrix.TranslationVector - camera.Entity.Transform.Position);
                        float distScalar;
                        Vector3.Dot(ref forwardVector, ref distVec, out distScalar);
                        distScalar = Math.Abs(distScalar);

                        var worldScale = frustumHeight * distScalar * UIComponent.FixedSizeVerticalUnit; // FrustumHeight already is 2*Tan(FOV/2)

                        worldMatrix.Row1 *= worldScale;
                        worldMatrix.Row2 *= worldScale;
                        worldMatrix.Row3 *= worldScale;
                    }

                    // If the UI component is not drawn fullscreen it should be drawn as a quad with world sizes corresponding to its actual size
                    worldMatrix = Matrix.Scaling(renderObject.Size / renderObject.Resolution) * worldMatrix;
                }

                // Rotation of Pi along 0x to go from UI space to world space
                worldMatrix.Row2 = -worldMatrix.Row2;
                worldMatrix.Row3 = -worldMatrix.Row3;

                Matrix worldViewMatrix;

                Matrix.Multiply(ref worldMatrix, ref camera.ViewMatrix, out worldViewMatrix);
                Matrix.Multiply(ref worldViewMatrix, ref camera.ProjectionMatrix, out WorldViewProjectionMatrix);
            }
Exemple #15
0
 partial void PickingUpdate(RenderUIElement renderUIElement, Viewport viewport, ref Matrix worldViewProj, GameTime drawTime, ref UIElement elementUnderMouseCursor);