private void RecursiveDrawWithClipping(RenderDrawContext context, UIElement element, ref Matrix worldViewProj, UIBatch batch, ref DepthStencilStateDescription dstate, SamplerState samplerState) { // not visible, remove children too if (!element.IsVisible) { return; } var renderingContext = batch.renderingContext as UIRenderingContext; var layoutingContext = batch.layoutingContext as LayoutingContext; var renderer = rendererManager.GetRenderer(element); renderingContext.DepthBias = element.DepthBias; // render the clipping region of the element if (element.ClipToBounds) { // flush current elements batch.End(); // render the clipping region batch.Begin(context.GraphicsContext, ref worldViewProj, BlendStates.ColorDisabled, samplerState, null, uiSystem.IncreaseStencilValueState, renderingContext.StencilTestReferenceValue); renderer.RenderClipping(element, renderingContext, batch); batch.End(); // update context and restart the batch renderingContext.StencilTestReferenceValue += 1; batch.Begin(context.GraphicsContext, ref worldViewProj, BlendStates.AlphaBlend, samplerState, null, dstate, renderingContext.StencilTestReferenceValue); } // render the design of the element renderer.RenderColor(element, renderingContext, batch); // render the children foreach (var child in element.VisualChildrenCollection) { RecursiveDrawWithClipping(context, child, ref worldViewProj, batch, ref dstate, samplerState); } // clear the element clipping region from the stencil buffer if (element.ClipToBounds) { // flush current elements batch.End(); renderingContext.DepthBias = element.MaxChildrenDepthBias; // render the clipping region batch.Begin(context.GraphicsContext, ref worldViewProj, BlendStates.ColorDisabled, samplerState, null, uiSystem.DecreaseStencilValueState, renderingContext.StencilTestReferenceValue); renderer.RenderClipping(element, renderingContext, batch); batch.End(); // update context and restart the batch renderingContext.StencilTestReferenceValue -= 1; batch.Begin(context.GraphicsContext, ref worldViewProj, BlendStates.AlphaBlend, samplerState, null, dstate, renderingContext.StencilTestReferenceValue); } }
public override void RenderColor(UIElement element, UIRenderingContext context, UIBatch Batch) { var modalElement = (ModalElement)element; // end the current UI image batching so that the overlay is written over it with correct transparency Batch.End(); var uiResolution = new Vector3(context.Resolution.X, context.Resolution.Y, 0); Batch.Begin(context.GraphicsContext, ref context.ViewProjectionMatrix, BlendStates.AlphaBlend, noStencilNoDepth, 0); Batch.DrawRectangle(ref identity, ref uiResolution, ref modalElement.OverlayColorInternal, context.DepthBias); Batch.End(); // ensure that overlay is written before possible next transparent element. // restart the image batch session Batch.Begin(context.GraphicsContext, ref context.ViewProjectionMatrix, BlendStates.AlphaBlend, KeepStencilValueState, context.StencilTestReferenceValue); context.DepthBias += 1; base.RenderColor(element, context, Batch); }
protected override void OnRendering(RenderContext context) { if (uiSystem.RootElement == null) { return; } var drawTime = game.DrawTime; var rootElement = uiSystem.RootElement; var virtualResolution = uiSystem.VirtualResolution; var updatableRootElement = (IUIElementUpdate)rootElement; // perform the time-based updates of the UI element updatableRootElement.Update(drawTime); // update the UI element disposition rootElement.Measure(virtualResolution); rootElement.Arrange(virtualResolution, false); // update the UI element hierarchical properties updatableRootElement.UpdateWorldMatrix(ref uiSystem.WorldMatrix, uiResolutionChanged); updatableRootElement.UpdateElementState(0); uiResolutionChanged = false; // set render targets and reset Depth buffer GraphicsDevice.SetDepthAndRenderTarget(GraphicsDevice.DepthStencilBuffer, GraphicsDevice.BackBuffer); GraphicsDevice.Clear(GraphicsDevice.DepthStencilBuffer, DepthStencilClearOptions.DepthBuffer | DepthStencilClearOptions.Stencil); // update the context time renderingContext.Time = game.DrawTime; // start the image draw session renderingContext.StencilTestReferenceValue = 0; batch.Begin(ref uiSystem.ViewProjectionInternal, GraphicsDevice.BlendStates.AlphaBlend, uiSystem.KeepStencilValueState, renderingContext.StencilTestReferenceValue); // Render the UI elements in the final render target ReccursiveDrawWithClipping(rootElement); // end the image draw session batch.End(); }
public override void RenderColor(UIElement element, UIRenderingContext context, UIBatch Batch) { base.RenderColor(element, context, Batch); var textBlock = (TextBlock)element; if (textBlock.Font == null || (textBlock.TextToDisplay?.Length ?? 0) == 0) { return; } var drawCommand = new SpriteFont.InternalUIDrawCommand { Color = textBlock.RenderOpacity * textBlock.TextColor, DepthBias = context.DepthBias, RealVirtualResolutionRatio = element.LayoutingContext.RealVirtualResolutionRatio, RequestedFontSize = textBlock.ActualTextSize, Batch = Batch, SnapText = context.ShouldSnapText && !textBlock.DoNotSnapText, Matrix = textBlock.WorldMatrixInternal, Alignment = textBlock.TextAlignment, VertAlignment = textBlock.TextVerticalAlignment, LineSpacingAdjustment = textBlock.LineSpacingAdjustment, TextBoxSize = new Vector2(textBlock.ActualWidth, textBlock.ActualHeight), }; if (textBlock.Font.FontType == SpriteFontType.SDF) { Batch.End(); Batch.BeginCustom(context.GraphicsContext, 1); } Batch.DrawString(textBlock.Font, textBlock.TextToDisplay, ref drawCommand); if (textBlock.Font.FontType == SpriteFontType.SDF) { Batch.End(); Batch.BeginCustom(context.GraphicsContext, 0); } }
public override void RenderColor(UIElement element, UIRenderingContext context, UIBatch Batch) { base.RenderColor(element, context, Batch); var editText = (EditText)element; if (editText.Font == null) { return; } // determine the image to draw in background of the edit text var fontScale = element.LayoutingContext.RealVirtualResolutionRatio; var color = editText.RenderOpacity * Color.White; var provider = editText.IsSelectionActive ? editText.ActiveImage : editText.MouseOverState == MouseOverState.MouseOverElement ? editText.MouseOverImage : editText.InactiveImage; var image = provider?.GetSprite(); if (image?.Texture != null) { Batch.DrawImage(image.Texture, ref editText.WorldMatrixInternal, ref image.RegionInternal, ref editText.RenderSizeInternal, ref image.BordersInternal, ref color, context.DepthBias, image.Orientation); } // calculate the size of the text region by removing padding var textRegionSize = new Vector2(editText.ActualWidth - editText.Padding.Left - editText.Padding.Right, editText.ActualHeight - editText.Padding.Top - editText.Padding.Bottom); var font = editText.Font; var caretColor = editText.RenderOpacity * editText.CaretColor; var offsetTextStart = 0f; var offsetAlignment = 0f; var selectionSize = 0f; // Draw the composition selection if (editText.Composition.Length > 0) { var imeSelectionColor = editText.RenderOpacity * editText.IMESelectionColor; RenderSelection(editText, context, editText.SelectionStart, editText.Composition.Length, imeSelectionColor, out offsetTextStart, out offsetAlignment, out selectionSize, Batch); } // Draw the regular selection else if (editText.IsSelectionActive) { var selectionColor = editText.RenderOpacity * editText.SelectionColor; RenderSelection(editText, context, editText.SelectionStart, editText.SelectionLength, selectionColor, out offsetTextStart, out offsetAlignment, out selectionSize, Batch); } // create the text draw command var drawCommand = new SpriteFont.InternalUIDrawCommand { Color = editText.RenderOpacity * editText.TextColor, DepthBias = context.DepthBias + 2, RealVirtualResolutionRatio = fontScale, RequestedFontSize = editText.ActualTextSize, Batch = Batch, SnapText = context.ShouldSnapText && !editText.DoNotSnapText, Matrix = editText.WorldMatrixInternal, Alignment = editText.TextAlignment, TextBoxSize = textRegionSize }; if (editText.Font.FontType == SpriteFontType.SDF) { Batch.End(); Batch.BeginCustom(context.GraphicsContext, 1); } // Draw the text Batch.DrawString(font, editText.TextToDisplay, ref drawCommand); if (editText.Font.FontType == SpriteFontType.SDF) { Batch.End(); Batch.BeginCustom(context.GraphicsContext, 0); } // Draw the cursor if (editText.IsCaretVisible) { var lineSpacing = editText.Font.GetTotalLineSpacing(editText.ActualTextSize); if (editText.Font.FontType != SpriteFontType.Dynamic) { lineSpacing *= editText.ActualTextSize / font.Size; } var sizeCaret = editText.CaretWidth / fontScale.X; var caretWorldMatrix = element.WorldMatrixInternal; caretWorldMatrix.M41 += offsetTextStart + offsetAlignment + (editText.CaretPosition > editText.SelectionStart? selectionSize: 0); var caretScaleVector = new Vector3(sizeCaret, editText.LineCount * lineSpacing, 0); Batch.DrawRectangle(ref caretWorldMatrix, ref caretScaleVector, ref caretColor, context.DepthBias + 3); } }
private void DrawInternal(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { base.Draw(context, renderView, renderViewStage, startIndex, endIndex); var uiProcessor = SceneInstance.GetCurrent(context.RenderContext).GetProcessor <UIRenderProcessor>(); if (uiProcessor == null) { return; } // evaluate the current draw time (game instance is null for thumbnails) var drawTime = game != null ? game.DrawTime : new GameTime(); // Prepare content required for Picking and MouseOver events var events = new List <PointerEvent>(); PickingPrepare(events); ulong poseCount = VirtualReality.VRDeviceSystem.GetSystem?.Device?.PoseCount ?? 0; // build the list of the UI elements to render UIElementState[] uiElementStates = new UIElementState[endIndex - startIndex]; if (uiElementStates.Length > 1 && GraphicsDevice.Platform == GraphicsPlatform.Vulkan) { Xenko.Core.Threading.Dispatcher.For(startIndex, endIndex, (index) => { initUIElementStates(context, renderView, renderViewStage, ref uiElementStates, index, index - startIndex, drawTime, events, poseCount); }); } else { for (int i = startIndex; i < endIndex; i++) { initUIElementStates(context, renderView, renderViewStage, ref uiElementStates, i, i - startIndex, drawTime, events, poseCount); } } events?.Clear(); lock (drawLocker) { UIBatch batch = getFreeBatch(context); var renderingContext = batch.renderingContext as UIRenderingContext; // update the rendering context renderingContext.GraphicsContext = context.GraphicsContext; renderingContext.Time = drawTime; DepthStencilStateDescription stencilState = uiSystem.KeepStencilValueState; // actually draw stuff for (int j = 0; j < uiElementStates.Length; j++) { var uiElementState = uiElementStates[j]; renderingContext.RenderObject = uiElementState.RenderObject; var rootElement = renderingContext.RenderObject.Page?.RootElement; if (rootElement == null || rootElement.IsVisible == false) { continue; } // update the rendering context values specific to this element renderingContext.ViewProjectionMatrix = uiElementState.WorldViewProjectionMatrix; switch (renderingContext.RenderObject.depthMode) { case Sprites.RenderSprite.SpriteDepthMode.Ignore: stencilState.DepthBufferWriteEnable = false; stencilState.DepthBufferEnable = false; break; case Sprites.RenderSprite.SpriteDepthMode.ReadOnly: stencilState.DepthBufferWriteEnable = false; stencilState.DepthBufferEnable = true; break; default: stencilState.DepthBufferWriteEnable = true; stencilState.DepthBufferEnable = true; break; case Sprites.RenderSprite.SpriteDepthMode.WriteOnly: stencilState.DepthBufferWriteEnable = true; stencilState.DepthBufferEnable = true; stencilState.DepthBufferFunction = CompareFunction.Always; break; } SamplerState samplerState; switch (renderingContext.RenderObject.Sampler) { default: samplerState = context.GraphicsDevice.SamplerStates.LinearClamp; break; case UIElementSampler.PointClamp: samplerState = context.GraphicsDevice.SamplerStates.PointClamp; break; case UIElementSampler.AnisotropicClamp: samplerState = context.GraphicsDevice.SamplerStates.AnisotropicClamp; break; } // start the image draw session renderingContext.StencilTestReferenceValue = 0; batch.Begin(context.GraphicsContext, ref uiElementState.WorldViewProjectionMatrix, BlendStates.AlphaBlend, samplerState, null, stencilState, renderingContext.StencilTestReferenceValue); // Render the UI elements in the final render target RecursiveDrawWithClipping(context, rootElement, ref uiElementState.WorldViewProjectionMatrix, batch, ref stencilState, samplerState); batch.End(); } ReturnBatch(batch); } }
public override void RenderColor(UIElement element, UIRenderingContext context, UIBatch Batch) { base.RenderColor(element, context, Batch); var scrollingText = (ScrollingText)element; if (scrollingText.Font == null || scrollingText.TextToDisplay == null) { return; } var offset = scrollingText.ScrollingOffset; var textWorldMatrix = element.WorldMatrix; textWorldMatrix.M41 += textWorldMatrix.M11 * offset; textWorldMatrix.M42 += textWorldMatrix.M12 * offset; textWorldMatrix.M43 += textWorldMatrix.M13 * offset; textWorldMatrix.M44 += textWorldMatrix.M14 * offset; // create the scrolling text draw command var drawCommand = new SpriteFont.InternalUIDrawCommand { Color = scrollingText.RenderOpacity * scrollingText.TextColor, VertAlignment = scrollingText.TextVerticalAlignment, LineSpacingAdjustment = scrollingText.LineSpacingAdjustment, DepthBias = context.DepthBias + 1, RealVirtualResolutionRatio = element.LayoutingContext.RealVirtualResolutionRatio, RequestedFontSize = scrollingText.ActualTextSize, Batch = Batch, SnapText = context.ShouldSnapText && !scrollingText.DoNotSnapText, Matrix = textWorldMatrix, Alignment = TextAlignment.Left, TextBoxSize = new Vector2(scrollingText.ActualWidth, scrollingText.ActualHeight) }; // flush the current content of the UI image batch Batch.End(); // draw a clipping mask Batch.Begin(context.GraphicsContext, ref context.ViewProjectionMatrix, BlendStates.ColorDisabled, IncreaseStencilValueState, context.StencilTestReferenceValue); Batch.DrawRectangle(ref element.WorldMatrixInternal, ref element.RenderSizeInternal, ref blackColor, context.DepthBias); Batch.End(); // draw the element it-self with stencil test value of "Context.Value + 1" Batch.Begin(context.GraphicsContext, ref context.ViewProjectionMatrix, BlendStates.AlphaBlend, KeepStencilValueState, context.StencilTestReferenceValue + 1); if (scrollingText.Font.FontType == SpriteFontType.SDF) { Batch.End(); Batch.BeginCustom(context.GraphicsContext, 1); } Batch.DrawString(scrollingText.Font, scrollingText.TextToDisplay, ref drawCommand); Batch.End(); // un-draw the clipping mask Batch.Begin(context.GraphicsContext, ref context.ViewProjectionMatrix, BlendStates.ColorDisabled, DecreaseStencilValueState, context.StencilTestReferenceValue + 1); Batch.DrawRectangle(ref element.WorldMatrixInternal, ref element.RenderSizeInternal, ref blackColor, context.DepthBias + 2); Batch.End(); // restart the Batch session Batch.Begin(context.GraphicsContext, ref context.ViewProjectionMatrix, BlendStates.AlphaBlend, KeepStencilValueState, context.StencilTestReferenceValue); }
private void DrawInternal(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { base.Draw(context, renderView, renderViewStage, startIndex, endIndex); var uiProcessor = SceneInstance.GetCurrent(context.RenderContext).GetProcessor <UIRenderProcessor>(); if (uiProcessor == null) { return; } // evaluate the current draw time (game instance is null for thumbnails) var drawTime = game != null ? game.DrawTime : new GameTime(); // Prepare content required for Picking and MouseOver events List <PointerEvent> events = new List <PointerEvent>(); PickingPrepare(events); // build the list of the UI elements to render ConcurrentCollector <UIElementState> uiElementStates = new ConcurrentCollector <UIElementState>(); if (GraphicsDevice.Platform == GraphicsPlatform.Vulkan) { Xenko.Core.Threading.Dispatcher.For(startIndex, endIndex, (index) => { initUIElementStates(context, renderView, renderViewStage, uiElementStates, index, drawTime, events); }); } else { for (int i = startIndex; i < endIndex; i++) { initUIElementStates(context, renderView, renderViewStage, uiElementStates, i, drawTime, events); } } events.Clear(); uiElementStates.Close(); lock (drawLocker) { UIBatch batch = getFreeBatch(context); var renderingContext = batch.renderingContext as UIRenderingContext; // update the rendering context renderingContext.GraphicsContext = context.GraphicsContext; renderingContext.Time = drawTime; DepthStencilStateDescription stencilState = uiSystem.KeepStencilValueState; // actually draw stuff for (int j = 0; j < uiElementStates.Count; j++) { var uiElementState = uiElementStates[j]; var renderObject = uiElementState.RenderObject; var rootElement = renderObject.Page?.RootElement; if (rootElement == null) { continue; } // update the rendering context values specific to this element renderingContext.Resolution = renderObject.Resolution; renderingContext.ViewProjectionMatrix = uiElementState.WorldViewProjectionMatrix; renderingContext.ShouldSnapText = renderObject.SnapText; renderingContext.IsFullscreen = renderObject.IsFullScreen; renderingContext.WorldMatrix3D = renderObject.WorldMatrix3D; switch (renderObject.depthMode) { case Sprites.RenderSprite.SpriteDepthMode.Ignore: stencilState.DepthBufferWriteEnable = false; stencilState.DepthBufferEnable = false; break; case Sprites.RenderSprite.SpriteDepthMode.ReadOnly: stencilState.DepthBufferWriteEnable = false; stencilState.DepthBufferEnable = true; break; default: stencilState.DepthBufferWriteEnable = true; stencilState.DepthBufferEnable = true; break; case Sprites.RenderSprite.SpriteDepthMode.WriteOnly: stencilState.DepthBufferWriteEnable = true; stencilState.DepthBufferEnable = false; break; } // start the image draw session renderingContext.StencilTestReferenceValue = 0; batch.Begin(context.GraphicsContext, ref uiElementState.WorldViewProjectionMatrix, BlendStates.AlphaBlend, stencilState, renderingContext.StencilTestReferenceValue); // Render the UI elements in the final render target RecursiveDrawWithClipping(context, rootElement, ref uiElementState.WorldViewProjectionMatrix, batch, ref stencilState); batch.End(); } ReturnBatch(batch); } }