상속: RenderObject
예제 #1
0
        partial void PickingUpdate(RenderUIElement renderUIElement, Viewport viewport, ref Matrix worldViewProj, GameTime drawTime, ref UIElement elementUnderMouseCursor)

        {
            if (renderUIElement.Page?.RootElement == null)
            {
                return;
            }

            var inverseZViewProj = worldViewProj;

            inverseZViewProj.Row3 = -inverseZViewProj.Row3;

            elementUnderMouseCursor = UpdateMouseOver(ref viewport, ref inverseZViewProj, renderUIElement);
            UpdateTouchEvents(ref viewport, ref inverseZViewProj, renderUIElement, drawTime);
        }
예제 #2
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);
            }
예제 #3
0
 partial void PickingUpdate(RenderUIElement renderUIElement, Viewport viewport, ref Matrix worldViewProj, GameTime drawTime, ref UIElement elementUnderMouseCursor);
예제 #4
0
            public void Update(RenderUIElement renderObject, CameraComponent camera)
            {
                var frustumHeight = 2 * (float)Math.Tan(MathUtil.DegreesToRadians(camera.VerticalFieldOfView) / 2);

                var worldMatrix = renderObject.WorldMatrix;

                if (renderObject.IsFullScreen)
                {
                    // If fullscreen UI, apply no rotation
                    worldMatrix = Matrix.Identity;
                }
                else
                {
                    // If billboard, rotate the UI element perpendicular to the camera view vector
                    Matrix.Invert(ref camera.ViewMatrix, out Matrix viewInverse);

                    if (renderObject.IsBillboard)
                    {
                        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;
                    }

                    if (renderObject.IsFixedSize)
                    {
                        var viewInverseForward = viewInverse.Forward;
                        viewInverseForward.Normalize();

                        var distanceVec = (worldMatrix.TranslationVector - viewInverse.TranslationVector);
                        Vector3.Dot(ref viewInverseForward, ref distanceVec, out float distance);
                        distance = Math.Abs(distance);

                        var worldScale = frustumHeight * distance * 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.Multiply(ref worldMatrix, ref camera.ViewMatrix, out Matrix worldViewMatrix);
                Matrix.Multiply(ref worldViewMatrix, ref camera.ProjectionMatrix, out WorldViewProjectionMatrix);
            }
예제 #5
0
 public UIElementState(RenderUIElement renderObject)
 {
     RenderObject = renderObject;
     WorldViewProjectionMatrix = Matrix.Identity;
 }
예제 #6
0
        private UIElement UpdateMouseOver(ref Viewport viewport, ref Matrix worldViewProj, RenderUIElement state)
        {
            if (input == null || !input.HasMouse)
            {
                return(null);
            }

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

            UIElement mouseOverElement = lastMouseOverElement;


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

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

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

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

            while (parent != commonElement && parent != null)
            {
                parent.RequiresMouseOverUpdate = false;

                parent.MouseOverState = MouseOverState.MouseOverNone;
                parent = parent.VisualParent;
            }


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

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

                    parent = parent.VisualParent;
                }
            }

            UIElementUnderMouseCursor = mouseOverElement;

            // update cached values
            state.LastMouseOverElement = mouseOverElement;
            state.LastMousePosition    = mousePosition;
            return(mouseOverElement);
        }
예제 #7
0
        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;
            }
        }