public override void Draw(GameTime gameTime, Frame frame) { var ir = new ImperativeRenderer(frame, Materials); ir.AutoIncrementLayer = true; ir.Clear(color: ClearColor); var rect1 = new Rectangle(0, 0, 32, 32); var rect2 = new Rectangle(1, 1, 30, 30); var drawSet = (Action <Rectangle, float>)((r, y) => { DrawRow(ref ir, 0f, y + 0f, SamplerState.PointClamp, r); DrawRow(ref ir, 0.5f, y + 1 + 64f, SamplerState.PointClamp, r); DrawRow(ref ir, 0f, (y + 3 + 128) + 0.5f, SamplerState.PointClamp, r); DrawRow(ref ir, 0f, y + 5 + 192f, SamplerState.LinearClamp, r); DrawRow(ref ir, 0.5f, y + 7 + 256f, SamplerState.LinearClamp, r); DrawRow(ref ir, 0f, (y + 9 + 320) + 0.5f, SamplerState.LinearClamp, r); }); drawSet(rect1, 0f); drawSet(rect2, (70f * 6)); var cornerSamplers = SamplerState.LinearClamp; ir.Draw(TestTexture, new Vector2(Graphics.PreferredBackBufferWidth - 1, Graphics.PreferredBackBufferHeight - 1), origin: new Vector2(1, 1), samplerState: cornerSamplers); ir.Draw(TestTexture, new Vector2(0, Graphics.PreferredBackBufferHeight - 1), origin: new Vector2(0, 1), samplerState: cornerSamplers); ir.Draw(TestTexture, new Vector2(Graphics.PreferredBackBufferWidth - 1, 0), origin: new Vector2(1, 0), samplerState: cornerSamplers); }
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; }
public void Rasterize(ref UIOperationContext context, ref ImperativeRenderer renderer, DecorationSettings settings, ref TData data) { switch (context.Pass) { case RasterizePasses.Below: if (Below != null) { Below(context, ref renderer, settings, ref data); } return; case RasterizePasses.Content: if (Content != null) { Content(context, ref renderer, settings, ref data); } return; case RasterizePasses.Above: if (Above != null) { Above(context, ref renderer, settings, ref data); } return; case RasterizePasses.ContentClip: if (ContentClip != null) { ContentClip(context, ref renderer, settings, ref data); } return; } }
public override void Draw(GameTime gameTime, Frame frame) { var ir = new ImperativeRenderer(frame, Materials, samplerState: SamplerState.LinearClamp); ir.AutoIncrementLayer = true; ir.Clear(color: ClearColor); Text.Position = TopLeft; Text2.LineBreakAtX = Text.LineBreakAtX = BottomRight.X - TopLeft.X; Text.WrapIndentation = Text2.WrapIndentation = Indent.Value ? 64 : 0; ir.OutlineRectangle(new Bounds(TopLeft, BottomRight), Color.Red); var layout = Text.Get(); if (ShowOutlines.Value) { foreach (var dc in layout.DrawCalls) { ir.OutlineRectangle(dc.EstimateDrawBounds(), Color.Blue); } } var m = Materials.Get(Materials.ScreenSpaceShadowedBitmap, blendState: BlendState.AlphaBlend); m.Parameters.ShadowColor.SetValue(new Vector4(0, 0, 0, 0.66f)); m.Parameters.ShadowOffset.SetValue(new Vector2(3.5f, 3.5f)); ir.OutlineRectangle(Bounds.FromPositionAndSize(Text.Position, layout.Size), Color.Yellow * 0.75f); ir.DrawMultiple(layout, material: m); if (Which.Value) { Text2.Position = TopLeft + new Vector2(0, layout.Size.Y + 20); layout = Text2.Get(); if (ShowOutlines.Value) { foreach (var dc in layout.DrawCalls) { ir.OutlineRectangle(dc.EstimateDrawBounds(), Color.Blue); } } ir.OutlineRectangle(Bounds.FromPositionAndSize(Text2.Position, layout.Size), Color.Yellow * 0.75f); ir.DrawMultiple(layout, material: m); } }
public override void Draw(GameTime gameTime, Frame frame) { var ir = new ImperativeRenderer(frame, Materials); ir.AutoIncrementLayer = true; ir.Clear(color: ClearColor); DrawRow(ref ir, 16f, 16f, SamplerState.PointClamp); DrawRow(ref ir, 16.5f, 16 + 64f, SamplerState.PointClamp); DrawRow(ref ir, 16f, (16 + 128) + 0.5f, SamplerState.PointClamp); DrawRow(ref ir, 16f, 16 + 192f, SamplerState.LinearClamp); DrawRow(ref ir, 16.5f, 16 + 256f, SamplerState.LinearClamp); DrawRow(ref ir, 16f, (16 + 320) + 0.5f, SamplerState.LinearClamp); }
private void DrawRow(ref ImperativeRenderer ir, float x, float y, SamplerState samplerState) { var sourceRect = new Rectangle(1, 1, 30, 30); ir.Draw(TestTexture, x, y, sourceRect, samplerState: samplerState); x += 64f; ir.Draw(TestTexture, x, y, sourceRect, scaleX: 2f, scaleY: 2f, samplerState: samplerState); x += 96f; for (float r = 0.1f; r < Math.PI / 2f; r += 0.2f) { ir.Draw(TestTexture, x, y, sourceRect, rotation: r, samplerState: samplerState); x += 64f; } }
private void DrawPerformanceStats(ref ImperativeRenderer ir) { const float scale = 1f; var text = PerformanceStats.GetText(this); using (var buffer = BufferPool <BitmapDrawCall> .Allocate(text.Length)) { var layout = Font.LayoutString(text, buffer, scale: scale); var layoutSize = layout.Size; var position = new Vector2(30f, 30f); var dc = layout.DrawCalls; ir.FillRectangle( Bounds.FromPositionAndSize(position, layoutSize), Color.Black ); ir.Layer += 1; ir.DrawMultiple(dc, position); } }
private void RasterizeAcceleratorOverlay( UIOperationContext context, ref ImperativeRenderer labelRenderer, ref ImperativeRenderer targetRenderer, Control control, InputID id, bool showFocused = false, Control forControl = null ) { if (id == null) { throw new ArgumentNullException("id"); } var gamePadMode = InputSources.FirstOrDefault() is GamepadVirtualKeyboardAndCursor; OverlayStringBuilder.Clear(); id.Format(OverlayStringBuilder, gamePadMode); RasterizeAcceleratorOverlay( context, ref labelRenderer, ref targetRenderer, control, OverlayStringBuilder, showFocused ); }
public override void Draw(GameTime gameTime, Frame frame) { using (var rtb = BatchGroup.ForRenderTarget(frame, -1, Rt)) { var ir = new ImperativeRenderer(rtb, Materials); ir.Clear(color: Color.Transparent); ir.SetViewport(new Rectangle(128, 128, 256, 256), true); ir.FillRectangle(new Rectangle(0, 0, 512, 512), Color.Black, customMaterial: Vpos); } { var ir = new ImperativeRenderer(frame, Materials) { AutoIncrementLayer = true }; ir.SetViewport(null, true); ir.Clear(color: Color.SteelBlue); const float scale = 0.65f; var pos = new Vector2(Graphics.PreferredBackBufferWidth, Graphics.PreferredBackBufferHeight) / 2f; ir.Draw( Texture, pos, origin: Vector2.One * 0.5f, scale: Vector2.One * scale, blendState: BlendState.Opaque, samplerState: SamplerState.LinearClamp ); ir.DrawString( Font, "Hello, World!", Vector2.Zero, blendState: BlendState.AlphaBlend, material: Materials.ScreenSpaceShadowedBitmap ); var sg = ir.MakeSubgroup(); sg.AutoIncrementLayer = true; sg.SetViewport(new Rectangle(128, 128, 512, 512), true); sg.FillRectangle(new Rectangle(0, 0, 1024, 1024), Color.Black, customMaterial: Vpos); sg.SetViewport(null, true); ir.Draw( Rt, new Vector2(1920 - 512, 0) ); } }
private void RasterizeAcceleratorOverlay( UIOperationContext context, ref ImperativeRenderer labelRenderer, ref ImperativeRenderer targetRenderer, AcceleratorInfo accel, bool showFocused = false, Control forControl = null ) { if (accel.Text != null) { RasterizeAcceleratorOverlay( context, ref labelRenderer, ref targetRenderer, accel.Target, accel.Text, showFocused, forControl ); } else { RasterizeAcceleratorOverlay( context, ref labelRenderer, ref targetRenderer, accel.Target, GetInputID(accel.Key, accel.Modifiers), showFocused, forControl ); } }
private void DrawRow(ref ImperativeRenderer ir, float x, float y, SamplerState samplerState, Rectangle sourceRect, bool mirror) { var tlState = samplerState; if ((x == 0) && (y == 0)) { tlState = SamplerState.LinearClamp; } ir.Draw(TestTexture, x, y, sourceRect, samplerState: tlState, mirrorX: mirror); x += 64f; ir.Draw(TestTexture, x, y, sourceRect, scaleX: 2f, scaleY: 2f, samplerState: samplerState, mirrorX: mirror); x += 96f; for (float r = 0.1f; r < Math.PI / 2f; r += 0.2f) { ir.Draw(TestTexture, x, y, sourceRect, rotation: r, samplerState: samplerState, mirrorX: mirror); x += 64f; } }
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; }
private void DrawHud(Frame frame) { Rectangle titleSafeArea = GraphicsDevice.Viewport.TitleSafeArea; Vector2 hudLocation = new Vector2(titleSafeArea.X, titleSafeArea.Y); Vector2 center = new Vector2(titleSafeArea.X + titleSafeArea.Width / 2.0f, titleSafeArea.Y + titleSafeArea.Height / 2.0f); // Draw time remaining. Uses modulo division to cause blinking when the // player is running out of time. string timeString = "TIME: " + level.TimeRemaining.Minutes.ToString("00") + ":" + level.TimeRemaining.Seconds.ToString("00"); Color timeColor; if (level.TimeRemaining > WarningTime || level.ReachedExit || (int)level.TimeRemaining.TotalSeconds % 2 == 0) { timeColor = Color.Yellow; } else { timeColor = Color.Red; } var renderer = new ImperativeRenderer(frame, materials, 100, blendState: BlendState.AlphaBlend); renderer.DrawString(hudFont, timeString, hudLocation, timeColor, sortKey: 1); renderer.DrawString(hudFont, timeString, hudLocation + Vector2.One, Color.Black, sortKey: 0); var timeHeight = hudFont.MeasureString(timeString).Y; hudLocation.Y = (float)Math.Floor(hudLocation.Y + (timeHeight * 1.2f)); var scoreText = "SCORE: " + level.Score; renderer.DrawString(hudFont, scoreText, hudLocation, Color.Yellow, sortKey: 1); renderer.DrawString(hudFont, scoreText, hudLocation + Vector2.One, Color.Black, sortKey: 0); // Determine the status overlay message to show. Texture2D status = null; if (level.TimeRemaining == TimeSpan.Zero) { if (level.ReachedExit) { status = winOverlay; } else { status = loseOverlay; } } else if (!level.Player.IsAlive) { status = diedOverlay; } if (status != null) { // Draw status message. Vector2 statusSize = new Vector2(status.Width, status.Height); renderer.Draw(status, center - statusSize / 2); } }
public override void Draw(GameTime gameTime, Frame frame) { if (false) { var stats = RenderManager.GetMemoryStatistics(); Console.WriteLine( "managed: {0:0000000}kb vertex: {1:0000000}kb index: {2:0000000}kb", (stats.ManagedIndexBytes + stats.ManagedVertexBytes) / 1024.0, stats.UnmanagedVertexBytes / 1024.0, stats.UnmanagedIndexBytes / 1024.0 ); } ClearBatch.AddNew(frame, -1, Materials.Clear, clearColor: ClearColor); const int width = 1280; const int height = 720; var options = new ParallelOptions { // MaxDegreeOfParallelism = 1 }; int layer = 0; Parallel.For( 0, height, options, // One batch per worker thread () => BitmapBatch.New( frame, // Suppress batch combining Interlocked.Increment(ref layer), Materials.ScreenSpaceBitmap ), (y, loopState, bb) => { var drawCall = new BitmapDrawCall(WhitePixel, new Vector2(0, y)); float fx = 0; var range = bb.ReserveSpace(width); var array = range.Array; var offset = range.Offset; for (int x = 0; x < width; x++, fx++) { drawCall.Texture = ((x % 2) == 0) ? WhitePixel : GrayPixel; drawCall.Position.X = fx; drawCall.MultiplyColor = new Color(255, x % 255, y % 255); array[offset + x] = drawCall; } return(bb); }, (bb) => bb.Dispose() ); var ir = new ImperativeRenderer( frame, Materials, blendState: BlendState.Opaque, depthStencilState: DepthStencilState.None, rasterizerState: RasterizerState.CullNone, worldSpace: false, layer: 9999 ); DrawPerformanceStats(ref ir); }
public void Rasterize(ref UIOperationContext context, ref ImperativeRenderer renderer) { }
public override void Draw(GameTime gameTime, Frame frame) { ClearBatch.AddNew(frame, 4, Materials.Clear, clearColor: new Color(16, 32, 48)); var alphaGeometry = Materials.Get(Materials.ScreenSpaceGeometry, blendState: BlendState.AlphaBlend); using (var gb = GeometryBatch.New(frame, 5, alphaGeometry)) { gb.AddGradientFilledQuad( Vector2.Zero, new Vector2(Graphics.PreferredBackBufferWidth, Graphics.PreferredBackBufferHeight), Color.DarkSlateGray, Color.DarkSlateGray, Color.SlateBlue, Color.SlateBlue ); } using (var gb = GeometryBatch.New(frame, 6, alphaGeometry)) { var alphaBlack = new Color(0, 0, 0, 192); var alphaBlack2 = new Color(0, 0, 0, 64); gb.AddQuadBorder( Playfield.Bounds.TopLeft + new Vector2(32 + 24, 0), Playfield.Bounds.BottomRight + new Vector2(-32 - 24, 0), alphaBlack2, alphaBlack, 24 ); } // Render the contents of the trail buffer to the screen using additive blending using (var bb = BitmapBatch.New(frame, 7, Materials.Trail)) { bb.Add(new BitmapDrawCall( TrailBuffer, Vector2.Zero, (float)TrailScale )); } // Render the paddles and ball to both the framebuffer and the trail buffer (note the different layer values) using (var gb = GeometryBatch.New(frame, 8, alphaGeometry)) using (var gb2 = GeometryBatch.New(frame, 9, alphaGeometry)) using (var trailBatch = GeometryBatch.New(frame, 2, alphaGeometry)) { foreach (var paddle in Paddles) { gb.AddFilledQuad( paddle.Bounds.TopLeft, paddle.Bounds.BottomRight, Color.White ); gb2.AddQuadBorder( paddle.Bounds.TopLeft, paddle.Bounds.BottomRight, Color.Black, Color.Black, 2.25f ); trailBatch.AddFilledQuad( paddle.Bounds.TopLeft, paddle.Bounds.BottomRight, Color.White ); } gb.AddFilledRing(Ball.Position, 0.0f, Ball.Radius, Color.White, Color.White); gb2.AddFilledRing(Ball.Position, Ball.Radius, Ball.Radius + 2.0f, Color.Black, Color.Black); trailBatch.AddFilledRing(Ball.Position, 0.0f, Ball.Radius, Color.White, Color.White); } // Render the score values using a stringbatch (unfortunately this uses spritebatch to render spritefonts :( ) { var ir = new ImperativeRenderer(frame, Materials, 10, blendState: BlendState.AlphaBlend); ir.DrawString( Font, String.Format("Player 1: {0:00}", Scores[0]), new Vector2(16, 16) ); var player2Text = String.Format("Player 2: {0:00}", Scores[1]); ir.DrawString( Font, player2Text, new Vector2(Graphics.PreferredBackBufferWidth - 16 - Font.MeasureString(player2Text).X, 16) ); } // The first stage of our frame involves selecting the trail buffer as our render target (note that it's layer 0) SetRenderTargetBatch.AddNew(frame, 0, TrailBuffer); if (FirstFrame) { // If it's the first time we've rendered, we erase the trail buffer since it could contain anything ClearBatch.AddNew(frame, 1, Materials.Clear, clearColor: Color.Black); FirstFrame = false; } else { // Otherwise, we fade out the contents of the trail buffer using (var gb = GeometryBatch.New(frame, 1, Materials.SubtractiveGeometry)) { gb.AddFilledQuad( new Bounds(Vector2.Zero, new Vector2(Graphics.PreferredBackBufferWidth, Graphics.PreferredBackBufferHeight)), new Color(12, 12, 12, 0) ); } } // After the trail buffer has been updated, we turn it off and begin rendering to the framebuffer. Note layer 3. SetRenderTargetBatch.AddNew(frame, 3, null); }
protected override void OnRasterize(ref UIOperationContext context, ref ImperativeRenderer renderer, DecorationSettings settings, IDecorator decorations) { }
protected virtual void OnRasterize(ref UIOperationContext context, ref ImperativeRenderer renderer, DecorationSettings settings, IDecorator decorations) { decorations?.Rasterize(ref context, ref renderer, settings); }
internal void SetContainer(DefaultMaterialSet materials, IBatchContainer container, int layer) { Container = container; ImperativeRenderer = new ImperativeRenderer(container, materials, layer); }
private void RasterizeAcceleratorOverlay( UIOperationContext context, ref ImperativeRenderer labelRenderer, ref ImperativeRenderer targetRenderer, Control control, AbstractString label, bool showFocused = false, Control forControl = null ) { if (control == null) { return; } if (!showFocused && (control == Focused) && !label.IsNull && (label.Length > 0)) { return; } if (label.Length <= 0) { return; } var box = control.GetRect(); if ((box.Width <= 1) || (box.Height <= 1)) { return; } var decorator = Decorations.AcceleratorTarget; var settings = new Decorations.DecorationSettings { Box = box, ContentBox = box }; decorator.Rasterize(ref context, ref targetRenderer, settings); var outlinePadding = 1f; decorator = Decorations.AcceleratorLabel; Color?textColor = null; decorator.GetTextSettings(ref context, default(ControlStates), out Material material, ref textColor, out _); var layout = decorator.GlyphSource.LayoutString(label, buffer: AcceleratorOverlayBuffer); var textScale = 1f; if (layout.Size.X > (box.Width - decorator.Padding.X)) { textScale = Math.Max(0.25f, (box.Width - decorator.Padding.X) / layout.Size.X); } var scaledSize = layout.Size * textScale; var labelTraits = new DenseList <string> { "above" }; var labelPosition = box.Position - new Vector2(0, scaledSize.Y + decorator.Padding.Y + outlinePadding); if (labelPosition.Y <= 0) { labelTraits[0] = "inside"; labelPosition = box.Position; } labelPosition.X = Arithmetic.Clamp(labelPosition.X, 0, CanvasSize.X - scaledSize.X); labelPosition.Y = Math.Max(0, labelPosition.Y); var labelBox = new RectF( labelPosition, scaledSize + decorator.Padding.Size ); if (IsObstructedByAnyPreviousBox(ref labelBox, forControl)) { labelBox.Left = box.Extent.X - labelBox.Width; } if (IsObstructedByAnyPreviousBox(ref labelBox, forControl)) { labelTraits[0] = "below"; labelBox.Left = labelPosition.X; labelBox.Top = box.Extent.Y + 1; // FIXME: Why the +1? } while (IsObstructedByAnyPreviousBox(ref labelBox, forControl)) { labelTraits[0] = "stacked"; labelBox.Left = box.Left; labelBox.Width = box.Width; labelBox.Top = labelBox.Extent.Y + 0.5f; } // HACK var labelContentBox = new RectF( labelBox.Position + new Vector2(decorator.Padding.Left, decorator.Padding.Top), scaledSize ); settings = new Decorations.DecorationSettings { Box = labelBox, ContentBox = box, Traits = labelTraits }; decorator.Rasterize(ref context, ref labelRenderer, settings); labelRenderer.DrawMultiple(layout.DrawCalls, offset: labelContentBox.Position.Floor(), scale: new Vector2(textScale), layer: 1); RasterizedOverlayBoxes.Add(new RasterizedOverlayBox { Control = forControl, ControlBox = box, LabelBox = labelBox }); }
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; } }
private void RasterizeAcceleratorOverlay(ref UIOperationContext context, ref ImperativeRenderer renderer) { var activeModal = ActiveModal; Control shiftTab = ResolveProxies(PickRotateFocusTarget(false, -1)), tab = ResolveProxies(PickRotateFocusTarget(false, 1)), ctrlShiftTab = (activeModal?.RetainFocus == true) ? null : ResolveProxies(PickRotateFocusTarget(true, -1)), ctrlTab = (activeModal?.RetainFocus == true) ? null : ResolveProxies(PickRotateFocusTarget(true, 1)); var targetGroup = renderer.MakeSubgroup(); var labelGroup = renderer.MakeSubgroup(); RasterizedOverlayBoxes.Clear(); if (Focused != null) { RasterizedOverlayBoxes.Add(new RasterizedOverlayBox { Control = Focused, ControlBox = Focused.GetRect(contentRect: true) }); } // FIXME: This looks confusing // RasterizeAcceleratorOverlay(context, ref labelGroup, ref targetGroup, Focused, null); var topLevelSource = TopLevelFocused as IAcceleratorSource; if (topLevelSource != null) { labelGroup = renderer.MakeSubgroup(); foreach (var accel in topLevelSource.Accelerators) { RasterizeAcceleratorOverlay(context, ref labelGroup, ref targetGroup, accel, true); } } RasterizeAcceleratorOverlay(context, ref labelGroup, ref targetGroup, tab, FocusForward); if (shiftTab != tab) { RasterizeAcceleratorOverlay(context, ref labelGroup, ref targetGroup, shiftTab, FocusBackward); } if ((ctrlTab != TopLevelFocused) || (ctrlShiftTab != TopLevelFocused)) { if (ctrlTab != tab) { RasterizeAcceleratorOverlay(context, ref labelGroup, ref targetGroup, ctrlTab, WindowFocusForward); } if (ctrlTab != ctrlShiftTab) { RasterizeAcceleratorOverlay(context, ref labelGroup, ref targetGroup, ctrlShiftTab, WindowFocusBackward); } } var focusedSource = Focused as IAcceleratorSource; if ((focusedSource != null) && (focusedSource != topLevelSource)) { labelGroup = renderer.MakeSubgroup(); foreach (var accel in focusedSource.Accelerators) { RasterizeAcceleratorOverlay(context, ref labelGroup, ref targetGroup, accel, true); } } }