Exemple #1
0
 private void NestedContextPassSetup(
     ref UIOperationContext context, ref RasterizePassSet passSet, ref ImperativeRenderer renderer, ref UIOperationContext passContext,
     out ImperativeRenderer contentRenderer, out RasterizePassSet childrenPassSet, out UIOperationContext contentContext,
     int previousStackDepth, ref int newStackDepth
     )
 {
     renderer.Layer += 1;
     passContext.Clone(out contentContext);
     contentRenderer = renderer.MakeSubgroup();
     if (ShouldClipContent)
     {
         newStackDepth = previousStackDepth + 1;
         contentRenderer.DepthStencilState = context.UIContext.GetStencilTest(newStackDepth);
         childrenPassSet = new RasterizePassSet(ref contentRenderer, newStackDepth, passSet.OverlayQueue);
     }
     else
     {
         contentRenderer.DepthStencilState =
             (previousStackDepth <= 0)
             ? DepthStencilState.None
             : context.UIContext.GetStencilTest(previousStackDepth);
         childrenPassSet = new RasterizePassSet(ref contentRenderer, newStackDepth, passSet.OverlayQueue);
     }
     renderer.Layer += 1;
 }
Exemple #2
0
        private void RasterizeIntoPrepassComposited(
            ref RasterizePassSet passSet, ref RectF compositeBox, ref BitmapDrawCall dc,
            bool enableCompositor, float effectiveOpacity
            )
        {
            if (MostRecentCompositeData == null)
            {
                MostRecentCompositeData = new CompositionData();
            }
            MostRecentCompositeData.DrawCall = dc;
            MostRecentCompositeData.Box      = compositeBox;
            var subgroup = passSet.Above.MakeSubgroup(
                before: BeforeComposite,
                after: AfterComposite,
                userData: this
                );

            ((BatchGroup)subgroup.Container).SetViewTransform(Appearance.HasTransformMatrix ? ApplyLocalTransformMatrix : null);
            subgroup.BlendState = RenderStates.PorterDuffOver;
            if (enableCompositor)
            {
                Appearance.Compositor.Composite(this, ref subgroup, ref dc, effectiveOpacity);
            }
            else
            {
                subgroup.Draw(ref dc, material: Appearance.CompositeMaterial);
            }
        }
Exemple #3
0
        private void RasterizeAllPassesTransformed(ref UIOperationContext context, ref RectF box, ref RasterizePassSet passSet)
        {
            if (MostRecentCompositeData == null)
            {
                MostRecentCompositeData = new CompositionData();
            }
            MostRecentCompositeData.Box = box;
            var subPassSet = new RasterizePassSet(ref passSet, this, ApplyGlobalTransformMatrix);

            RasterizeAllPasses(ref context, ref box, ref subPassSet, false);
        }
Exemple #4
0
        private void RasterizeIntoPrepass(
            ref UIOperationContext context, RasterizePassSet passSet, float opacity,
            ref RectF box, ref RectF compositeBox,
            UIContext.ScratchRenderTarget rt, bool enableCompositor
            )
        {
            UIOperationContext compositionContext;

            context.Clone(out compositionContext);
            compositionContext.Opacity = 1.0f;
            UpdateVisibleRegion(ref compositionContext, ref box);

            var newPassSet = new RasterizePassSet(ref rt.Renderer, 0, passSet.OverlayQueue);

            // newPassSet.Above.RasterizeEllipse(box.Center, Vector2.One * 6f, Color.White * 0.7f);
            RasterizeAllPasses(ref compositionContext, ref box, ref newPassSet, true);
            rt.Renderer.Layer += 1;
            var pos = Appearance.HasTransformMatrix ? Vector2.Zero : compositeBox.Position.Floor();
            // FIXME: Is this the right layer?
            var sourceRect = new Rectangle(
                (int)compositeBox.Left, (int)compositeBox.Top,
                (int)compositeBox.Width, (int)compositeBox.Height
                );
            var effectiveOpacity = context.Opacity * opacity;
            var dc = new BitmapDrawCall(
                // FIXME
                rt.Instance.Get(), pos,
                GameExtensionMethods.BoundsFromRectangle((int)Context.CanvasSize.X, (int)Context.CanvasSize.Y, in sourceRect),
                new Color(effectiveOpacity, effectiveOpacity, effectiveOpacity, effectiveOpacity), scale: 1.0f / Context.ScratchScaleFactor
                );

            if (Appearance.HasTransformMatrix || enableCompositor)
            {
                RasterizeIntoPrepassComposited(ref passSet, ref compositeBox, ref dc, enableCompositor, effectiveOpacity);
            }
            else if (Appearance.Overlay)
            {
                passSet.OverlayQueue.Add(ref dc);
            }
            else
            {
                GetMaterialAndBlendStateForCompositing(out Material compositeMaterial, out BlendState compositeBlendState);
                passSet.Above.Draw(
                    ref dc, material: compositeMaterial,
                    blendState: compositeBlendState ?? RenderStates.PorterDuffOver
                    );
                passSet.Above.Layer += 1;
            }
        }
Exemple #5
0
        private void NestedContextPassTeardown(
            ref UIOperationContext context, ref DecorationSettings settings, IDecorator decorations,
            ref RasterizePassSet passSet, ref ImperativeRenderer contentRenderer, ref UIOperationContext contentContext,
            int previousStackDepth
            )
        {
            // If this is the first stencil pass instead of a nested one, clear the stencil buffer
            if (passSet.StackDepth < 1)
            {
                contentRenderer.Clear(stencil: 0, layer: -9999);
            }
            else
            {
                // Erase any siblings' clip regions
                contentRenderer.DepthStencilState = context.UIContext.GetStencilRestore(previousStackDepth);
                contentRenderer.FillRectangle(new Rectangle(-1, -1, 9999, 9999), Color.Transparent, blendState: RenderStates.DrawNone, layer: -1000);
            }

            contentRenderer.DepthStencilState = context.UIContext.GetStencilWrite(previousStackDepth);

            // FIXME: Separate context?
            contentContext.Pass = RasterizePasses.ContentClip;

            // FIXME
            var temp = settings;

            ApplyClipMargins(ref contentContext, ref temp.Box);

            var crLayer = contentRenderer.Layer;

            contentRenderer.Layer = -999;
            settings.State        = default(ControlStates);
            decorations?.Rasterize(ref contentContext, ref contentRenderer, temp);

            contentRenderer.Layer = crLayer;

            // passSet.NextReferenceStencil = childrenPassSet.NextReferenceStencil;
        }
Exemple #6
0
        private void RasterizePass(
            ref UIOperationContext context,
            ref DecorationSettings settings, IDecorator decorations,
            bool compositing, ref RasterizePassSet passSet,
            ref ImperativeRenderer renderer, RasterizePasses pass
            )
        {
            UIOperationContext passContext;

            context.Clone(out passContext);
            passContext.Pass = pass;
            var hasNestedContext = (pass == RasterizePasses.Content) &&
                                   (ShouldClipContent || (HasChildren && CreateNestedContextForChildren));

            if (hasNestedContext)
            {
                UpdateVisibleRegion(ref passContext, ref settings.Box);
            }

            // FIXME: The memset for these actually burns a measurable amount of time
            ImperativeRenderer contentRenderer;
            RasterizePassSet   childrenPassSet;
            UIOperationContext contentContext;

            int previousStackDepth = passSet.StackDepth, newStackDepth = previousStackDepth;

            // For clipping we need to create a separate batch group that contains all the rasterization work
            //  for our children. At the start of it we'll generate the stencil mask that will be used for our
            //  rendering operation(s).
            if (hasNestedContext)
            {
                NestedContextPassSetup(
                    ref context, ref passSet, ref renderer, ref passContext,
                    out contentRenderer, out childrenPassSet, out contentContext,
                    previousStackDepth, ref newStackDepth
                    );
            }
            else
            {
                contentContext  = passContext;
                childrenPassSet = default;
                contentRenderer = default;
            }

            // TODO: all the copying of settings here burns CPU time

            if (HasPreRasterizeHandler && (pass == RasterizePasses.Content))
            {
                OnPreRasterize(ref contentContext, settings, decorations);
            }

            if (hasNestedContext)
            {
                OnRasterize(ref contentContext, ref contentRenderer, settings, decorations);
            }
            else
            {
                OnRasterize(ref contentContext, ref renderer, settings, decorations);
            }

            if ((pass == RasterizePasses.Content) && HasChildren)
            {
                if (hasNestedContext)
                {
                    OnRasterizeChildren(ref contentContext, ref childrenPassSet, settings);
                }
                else
                {
                    // FIXME: Save/restore layers?
                    OnRasterizeChildren(ref contentContext, ref passSet, settings);
                }
            }

            if (hasNestedContext)
            {
                // GROSS OPTIMIZATION HACK: Detect that any rendering operation(s) occurred inside the
                //  group and if so, set up the stencil mask so that they will be clipped.
                if (ShouldClipContent && !contentRenderer.Container.IsEmpty)
                {
                    NestedContextPassTeardown(
                        ref context, ref settings, decorations, ref passSet,
                        ref contentRenderer, ref contentContext, previousStackDepth
                        );
                }

                renderer.Layer += 1;
            }
        }
Exemple #7
0
        private void RasterizeComposited(ref UIOperationContext context, ref RectF box, ref RasterizePassSet passSet, float opacity, bool enableCompositor)
        {
            // HACK: Create padding around the element for drop shadows
            var padding = Appearance.Compositor?.Padding ?? Context.CompositorPaddingPx;

            box.SnapAndInset(out Vector2 tl, out Vector2 br, -padding);
            // Don't overflow the edges of the canvas with padding, it'd produce garbage pixels
            var canvasRect = context.UIContext.CanvasRect;

            canvasRect.Clamp(ref tl);
            canvasRect.Clamp(ref br);

            var compositeBox = new RectF(tl, br - tl);
            var srt          = context.UIContext.GetScratchRenderTarget(context.Prepass, ref compositeBox);

            if (context.RenderTargetStack.Count > 0)
            {
                context.RenderTargetStack[context.RenderTargetStack.Count - 1].Dependencies.Add(srt);
            }
            context.RenderTargetStack.Add(srt);
            try {
                // passSet.Above.RasterizeRectangle(box.Position, box.Extent, 1f, Color.Red * 0.1f);
                RasterizeIntoPrepass(ref context, passSet, opacity, ref box, ref compositeBox, srt, enableCompositor);
                // passSet.Above.RasterizeEllipse(box.Center, Vector2.One * 3f, Color.White);
            } finally {
                context.RenderTargetStack.RemoveTail(1);
                context.UIContext.ReleaseScratchRenderTarget(srt.Instance);
            }
        }
Exemple #8
0
 protected virtual void OnRasterizeChildren(ref UIOperationContext context, ref RasterizePassSet passSet, DecorationSettings settings)
 {
 }
Exemple #9
0
        public bool Rasterize(ref UIOperationContext context, ref RasterizePassSet passSet, float opacity = 1)
        {
            // HACK: Do this first since it fires opacity change events
            var hidden = false;

            var tweenOpacity = GetOpacity(context.NowL);

            opacity *= tweenOpacity;

            if (opacity <= 0)
            {
                hidden = true;
            }
            if (!Visible)
            {
                hidden = true;
            }

            var  box = default(RectF);
            bool isZeroSized = false, isOutOfView = false,
                 transformActive = context.TransformActive || Appearance.HasTransformMatrix;

            if (IsLayoutInvalid)
            {
                hidden = true;
            }
            else
            {
                box = GetRect();
                Vector2 ext  = box.Extent,
                        vext = context.VisibleRegion.Extent;
                // HACK: There might be corner cases where you want to rasterize a zero-sized control...
                isZeroSized = (box.Width <= 0) || (box.Height <= 0);
                isOutOfView = (ext.X < context.VisibleRegion.Left) ||
                              (ext.Y < context.VisibleRegion.Top) ||
                              (box.Left > vext.X) ||
                              (box.Top > vext.Y);

                RasterizeDebugOverlays(ref context, ref passSet, box);
            }

#if DETECT_DOUBLE_RASTERIZE
            if (!RasterizeIsPending)
            {
                throw new Exception("Double rasterize detected");
            }
            RasterizeIsPending = false;
#endif

            if (isZeroSized)
            {
                hidden = true;
            }

            // Only visibility cull controls that have a parent and aren't overlaid.
            if (isOutOfView && (WeakParent != null) && !Appearance.Overlay && !transformActive)
            {
                hidden = true;
            }

            if (hidden)
            {
                // HACK: Ensure pre-rasterize handlers run for hidden controls, because the handler
                //  may be doing something important like updating animations or repainting a buffer
                RunPreRasterizeHandlerForHiddenControl(ref context, ref box);
                return(false);
            }

            Appearance.AutoClearTransform(context.NowL);

            var enableCompositor   = Appearance.Compositor?.WillComposite(this, opacity) == true;
            var hasTransformMatrix = Appearance.HasTransformMatrix &&
                                     // HACK: If the current transform matrix is the identity matrix, suppress composition
                                     //  this allows simple transform animations that end at the identity matrix to work
                                     //  without explicitly clearing the transform after the animation is over.
                                     Appearance.GetTransform(out Matrix transform, context.NowL) &&
                                     (transform != Matrix.Identity);

            var needsComposition   = NeedsComposition(opacity < 1, hasTransformMatrix) || enableCompositor;
            var oldOpacity         = context.Opacity;
            var oldTransformActive = context.TransformActive;
            context.TransformActive = context.TransformActive || hasTransformMatrix;
            try {
                if (!needsComposition)
                {
                    context.Opacity *= opacity;
                    if (hasTransformMatrix)
                    {
                        RasterizeAllPassesTransformed(ref context, ref box, ref passSet);
                    }
                    else
                    {
                        RasterizeAllPasses(ref context, ref box, ref passSet, false);
                    }
                }
                else
                {
                    RasterizeComposited(ref context, ref box, ref passSet, opacity, enableCompositor);
                }
            } finally {
                context.Opacity         = oldOpacity;
                context.TransformActive = oldTransformActive;
            }

            return(true);
        }
Exemple #10
0
        private void RasterizeDebugOverlays(ref UIOperationContext context, ref RasterizePassSet passSet, RectF rect)
        {
            if (!ShowDebugBoxes && !ShowDebugBreakMarkers && !ShowDebugMargins && !ShowDebugPadding && !ShowDebugBoxesForLeavesOnly)
            {
                return;
            }

            var mouseIsOver = rect.Contains(context.MousePosition);
            var alpha       = mouseIsOver ? 1.0f : 0.5f;
            // HACK: Show outlines for controls that don't have any children or contain the mouse position
            var isLeaf = (((this as IControlContainer)?.Children?.Count ?? 0) == 0) || mouseIsOver;

            int?layer = null;

            if (ShowDebugBoxes || (ShowDebugBoxesForLeavesOnly && isLeaf))
            {
                passSet.Above.RasterizeRectangle(
                    rect.Position, rect.Extent, 0f, 1f, Color.Transparent, Color.Transparent,
                    GetDebugBoxColor(context.Depth) * alpha, layer: layer
                    );
            }

            if (!context.Layout.TryGetFlags(LayoutKey, out ControlFlags flags))
            {
                return;
            }

            if (ShowDebugMargins)
            {
                RasterizeDebugMargins(ref context, ref passSet, ref rect, context.Layout.GetMargins(LayoutKey), 1f, Color.Green, layer);
            }

            if (ShowDebugPadding)
            {
                RasterizeDebugMargins(ref context, ref passSet, ref rect, context.Layout.GetPadding(LayoutKey), -1f, Color.Yellow, layer);
            }

            if (ShowDebugBreakMarkers && mouseIsOver && flags.IsBreak())
            {
                rect = new RectF(
                    new Vector2(rect.Left - 1.5f, rect.Center.Y - 7.5f),
                    new Vector2(6.5f, 15)
                    );

                var     facingRight = false;
                Vector2 a           = !facingRight ? rect.Extent : rect.Position,
                        b           = !facingRight
                        ? new Vector2(rect.Position.X, rect.Center.Y)
                        : new Vector2(rect.Extent.X, rect.Center.Y),
                        c = !facingRight
                        ? new Vector2(rect.Extent.X, rect.Position.Y)
                        : new Vector2(rect.Position.X, rect.Extent.Y);

                var arrowColor =
                    flags.IsFlagged(ControlFlags.Layout_ForceBreak)
                        ? Color.White
                        : Color.Yellow;

                passSet.Above.RasterizeTriangle(
                    a, b, c, radius: 0f, outlineRadius: 1f,
                    innerColor: arrowColor * alpha, outerColor: arrowColor * alpha,
                    outlineColor: Color.Black * (alpha * 0.8f)
                    );
            }
        }
Exemple #11
0
        private void RasterizeDebugMargins(ref UIOperationContext context, ref RasterizePassSet passSet, ref RectF rect, Margins margins, float direction, Color color, int?layer)
        {
            float lineWidth = 1.33f, extentLength = 16f, extentThickness = 0.75f;
            var   exteriorRect = rect;

            exteriorRect.Left   -= margins.Left * direction;
            exteriorRect.Top    -= margins.Top * direction;
            exteriorRect.Width  += margins.X * direction;
            exteriorRect.Height += margins.Y * direction;
            var center = rect.Center;

            if (margins.Left > 0)
            {
                passSet.Above.RasterizeRectangle(
                    new Vector2(exteriorRect.Left, center.Y - lineWidth),
                    new Vector2(rect.Left, center.Y + lineWidth),
                    0, color, layer: layer
                    );
                passSet.Above.RasterizeRectangle(
                    new Vector2(exteriorRect.Left, center.Y - extentLength),
                    new Vector2(exteriorRect.Left + extentThickness, center.Y + extentLength),
                    0, color, layer: layer
                    );
            }

            if (margins.Top > 0)
            {
                passSet.Above.RasterizeRectangle(
                    new Vector2(center.X - lineWidth, exteriorRect.Top),
                    new Vector2(center.X + lineWidth, rect.Top),
                    0, color, layer: layer
                    );
                passSet.Above.RasterizeRectangle(
                    new Vector2(center.X - extentLength, exteriorRect.Top),
                    new Vector2(center.X + extentLength, exteriorRect.Top + extentThickness),
                    0, color, layer: layer
                    );
            }

            if (margins.Right > 0)
            {
                passSet.Above.RasterizeRectangle(
                    new Vector2(exteriorRect.Extent.X, center.Y - lineWidth),
                    new Vector2(rect.Extent.X, center.Y + lineWidth),
                    0, color, layer: layer
                    );
                passSet.Above.RasterizeRectangle(
                    new Vector2(exteriorRect.Extent.X, center.Y - extentLength),
                    new Vector2(exteriorRect.Extent.X - extentThickness, center.Y + extentLength),
                    0, color, layer: layer
                    );
            }

            if (margins.Bottom > 0)
            {
                passSet.Above.RasterizeRectangle(
                    new Vector2(center.X - lineWidth, exteriorRect.Extent.Y),
                    new Vector2(center.X + lineWidth, rect.Extent.Y),
                    0, color, layer: layer
                    );
                passSet.Above.RasterizeRectangle(
                    new Vector2(center.X - extentLength, exteriorRect.Extent.Y),
                    new Vector2(center.X + extentLength, exteriorRect.Extent.Y + extentThickness),
                    0, color, layer: layer
                    );
            }
        }
Exemple #12
0
        private void RasterizeAllPasses(ref UIOperationContext context, ref RectF box, ref RasterizePassSet passSet, bool compositing)
        {
            try {
                if (Appearance.DecorationProvider != null)
                {
                    UIOperationContext.PushDecorationProvider(ref context, Appearance.DecorationProvider);
                }

                var decorations = GetDecorator(context.DecorationProvider, context.DefaultDecorator);
                var contentBox  = GetRect(contentRect: true);
                var state       = GetCurrentState(ref context);
                var settings    = MakeDecorationSettings(ref box, ref contentBox, state, compositing);
                if (!IsPassDisabled(RasterizePasses.Below, decorations))
                {
                    RasterizePass(ref context, ref settings, decorations, compositing, ref passSet, ref passSet.Below, RasterizePasses.Below);
                }
                if (!IsPassDisabled(RasterizePasses.Content, decorations))
                {
                    RasterizePass(ref context, ref settings, decorations, compositing, ref passSet, ref passSet.Content, RasterizePasses.Content);
                }
                if (!IsPassDisabled(RasterizePasses.Above, decorations))
                {
                    RasterizePass(ref context, ref settings, decorations, compositing, ref passSet, ref passSet.Above, RasterizePasses.Above);
                }
            } finally {
                if (Appearance.DecorationProvider != null)
                {
                    UIOperationContext.PopDecorationProvider(ref context);
                }
            }
        }