public override void RenderOverride(RenderContext localRenderContext) { base.RenderOverride(localRenderContext); AllocFont(); HorizontalTextAlignEnum horzAlign = HorizontalTextAlignEnum.Left; if (HorizontalContentAlignment == HorizontalAlignmentEnum.Right) { horzAlign = HorizontalTextAlignEnum.Right; } else if (HorizontalContentAlignment == HorizontalAlignmentEnum.Center) { horzAlign = HorizontalTextAlignEnum.Center; } VerticalTextAlignEnum vertAlign = VerticalTextAlignEnum.Top; if (VerticalContentAlignment == VerticalAlignmentEnum.Bottom) { vertAlign = VerticalTextAlignEnum.Bottom; } else if (VerticalContentAlignment == VerticalAlignmentEnum.Center) { vertAlign = VerticalTextAlignEnum.Center; } Color4 color = ColorConverter.FromColor(Color); color.Alpha *= (float)localRenderContext.Opacity; _asset.Render(_innerRect, horzAlign, vertAlign, color, Wrap, true, localRenderContext.ZOrder, Scroll, (float)ScrollSpeed, (float)ScrollDelay, localRenderContext.Transform); }
public override void RenderOverride(RenderContext localRenderContext) { base.RenderOverride(localRenderContext); AllocFont(); HorizontalTextAlignEnum horzAlign = HorizontalTextAlignEnum.Left; if (HorizontalContentAlignment == HorizontalAlignmentEnum.Right) { horzAlign = HorizontalTextAlignEnum.Right; } else if (HorizontalContentAlignment == HorizontalAlignmentEnum.Center) { horzAlign = HorizontalTextAlignEnum.Center; } VerticalTextAlignEnum vertAlign = VerticalTextAlignEnum.Top; if (VerticalContentAlignment == VerticalAlignmentEnum.Bottom) { vertAlign = VerticalTextAlignEnum.Bottom; } else if (VerticalContentAlignment == VerticalAlignmentEnum.Center) { vertAlign = VerticalTextAlignEnum.Center; } Color4 color = ColorConverter.FromColor(Color); color.Alpha *= (float)localRenderContext.Opacity; // Update text cursor if ((_cursorShapeInvalid || _cursorBrushInvalid) && CursorState == TextCursorState.Visible) { string textBeforeCaret = VisibleText; textBeforeCaret = string.IsNullOrEmpty(textBeforeCaret) ? string.Empty : textBeforeCaret.Substring(0, CaretIndex); float caretX = _asset.TextWidth(textBeforeCaret); float textHeight = _asset.TextHeight(1); float textInsetY; switch (vertAlign) { case VerticalTextAlignEnum.Bottom: textInsetY = _innerRect.Height - textHeight; break; case VerticalTextAlignEnum.Center: textInsetY = (_innerRect.Height - textHeight) / 2; break; default: // VerticalTextAlignEnum.Top textInsetY = 0; break; } if (_virtualPosition + caretX < 10) { _virtualPosition = _innerRect.Width / 3 - caretX; } if (_virtualPosition + caretX > _innerRect.Width - 10) { _virtualPosition = _innerRect.Width * 2 / 3 - caretX; } Bound(ref _virtualPosition, -caretX, 0); RectangleF cursorBounds = new RectangleF(_innerRect.X + _virtualPosition + caretX, _innerRect.Y + textInsetY, CURSOR_THICKNESS, textHeight); UpdateCursorShape(cursorBounds, localRenderContext.ZOrder); } // Render text _asset.Render(_innerRect, horzAlign, vertAlign, _virtualPosition, color, localRenderContext.ZOrder, localRenderContext.Transform); // Render text cursor if (_cursorBrush != null && CursorState == TextCursorState.Visible) { _cursorBrush.BeginRenderBrush(_cursorContext, localRenderContext); _cursorContext.Render(0); _cursorBrush.EndRender(); } }
/// <summary> /// Simplified render method to draw the text with a given text offset. This can be used for text edit controls where the text is /// shifted horizontally against its textbox. /// </summary> /// <param name="textBox">The box where the text should be drawn.</param> /// <param name="horzAlignment">The horizontal alignment.</param> /// <param name="vertAlignment">The vertical alignment.</param> /// <param name="offsetX">Horizontal offset of the text in relation to its text box. A negative offset will make the text start left of its /// normal position.</param> /// <param name="color">The color.</param> /// <param name="zOrder">A value indicating the depth (and thus position in the visual heirachy) that this element should be rendered at.</param> /// <param name="finalTransform">The final combined layout/render-transform.</param> public void Render(RectangleF textBox, HorizontalTextAlignEnum horzAlignment, VerticalTextAlignEnum vertAlignment, float offsetX, Color4 color, float zOrder, Matrix finalTransform) { if (!IsAllocated || _lastWrap || _textChanged) { Allocate(textBox.Width, false); if (!IsAllocated) return; } // Prepare horizontal alignment info for shader. X is position offset, Y is multiplyer for line width. Vector4 alignParam; switch (horzAlignment) { case HorizontalTextAlignEnum.Center: alignParam = new Vector4(textBox.Width / 2.0f, -0.5f, zOrder, 1.0f); break; case HorizontalTextAlignEnum.Right: alignParam = new Vector4(textBox.Width, -1.0f, zOrder, 1.0f); break; //case TextAlignEnum.Left: default: alignParam = new Vector4(0.0f, 0.0f, zOrder, 1.0f); break; } // Do vertical alignment by adjusting yPosition float yPosition = 0.0f; switch (vertAlignment) { case VerticalTextAlignEnum.Bottom: yPosition = Math.Max(textBox.Height - _lastTextSize.Height, 0.0f); break; case VerticalTextAlignEnum.Center: yPosition += Math.Max((textBox.Height - _lastTextSize.Height) / 2.0f, 0.0f); break; //case TextAlignEnum.Top: // Do nothing } // No fading _effect = ContentManager.Instance.GetEffect(EFFECT_FONT); // Render _effect.Parameters[PARAM_COLOR] = color; _effect.Parameters[PARAM_ALIGNMENT] = alignParam; _effect.Parameters[PARAM_SCROLL_POSITION] = new Vector4(offsetX, yPosition, 0.0f, 0.0f); _effect.Parameters[PARAM_TEXT_RECT] = new Vector4(textBox.Left, textBox.Top, textBox.Width, textBox.Height); DoRender(finalTransform); _lastTimeUsed = SkinContext.FrameRenderingStartTime; }
/// <summary> /// Standard draw method for this text. /// </summary> /// <param name="textBox">The box where the text should be drawn.</param> /// <param name="horzAlignment">The horizontal alignment.</param> /// <param name="vertAlignment">The vertical alignment.</param> /// <param name="color">The color.</param> /// <param name="wrap">If <c>true</c> then text will be word-wrapped to fit the <paramref name="textBox"/>.</param> /// <param name="fade">If <c>true</c> then text will be faded at the edge of the <paramref name="textBox"/>.</param> /// <param name="zOrder">A value indicating the depth (and thus position in the visual heirachy) that this element should be rendered at.</param> /// <param name="scrollMode">Text scrolling behaviour.</param> /// <param name="scrollSpeed">Text scrolling speed in units (pixels at original skin size) per second.</param> /// <param name="scrollDelay">Text scrolling delay in seconds.</param> /// <param name="finalTransform">The final combined layout/render-transform.</param> public void Render(RectangleF textBox, HorizontalTextAlignEnum horzAlignment, VerticalTextAlignEnum vertAlignment, Color4 color, bool wrap, bool fade, float zOrder, TextScrollEnum scrollMode, float scrollSpeed, float scrollDelay, Matrix finalTransform) { if (!IsAllocated || wrap != _lastWrap || _textChanged || (wrap && textBox.Width != _lastTextBoxWidth)) { Allocate(textBox.Width, wrap); if (!IsAllocated) return; } // Update scrolling TextScrollEnum actualScrollMode = scrollMode; if (scrollMode != TextScrollEnum.None && _lastTimeUsed != DateTime.MinValue) actualScrollMode = UpdateScrollPosition(textBox, scrollMode, scrollSpeed, scrollDelay); // Prepare horizontal alignment info for shader. X is position offset, Y is multiplyer for line width. Vector4 alignParam; switch (horzAlignment) { case HorizontalTextAlignEnum.Center: alignParam = new Vector4(textBox.Width / 2.0f, -0.5f, zOrder, 1.0f); break; case HorizontalTextAlignEnum.Right: alignParam = new Vector4(textBox.Width, -1.0f, zOrder, 1.0f); break; //case TextAlignEnum.Left: default: alignParam = new Vector4(0.0f, 0.0f, zOrder, 1.0f); break; } // Do vertical alignment by adjusting yPosition float yPosition = 0.0f; switch (vertAlignment) { case VerticalTextAlignEnum.Bottom: yPosition = Math.Max(textBox.Height - _lastTextSize.Height, 0.0f); break; case VerticalTextAlignEnum.Center: yPosition += Math.Max((textBox.Height - _lastTextSize.Height) / 2.0f, 0.0f); break; //case TextAlignEnum.Top: // Do nothing } // Do we need to add fading edges? Vector4 fadeBorder; if (fade && CalculateFadeBorder(actualScrollMode, textBox, horzAlignment, out fadeBorder)) { _effect = ContentManager.Instance.GetEffect(EFFECT_FONT_FADE); _effect.Parameters[PARAM_FADE_BORDER] = fadeBorder; } else _effect = ContentManager.Instance.GetEffect(EFFECT_FONT); // Render _effect.Parameters[PARAM_COLOR] = color; _effect.Parameters[PARAM_ALIGNMENT] = alignParam; _effect.Parameters[PARAM_SCROLL_POSITION] = new Vector4(_scrollPos.X, _scrollPos.Y + yPosition, 0.0f, 0.0f); _effect.Parameters[PARAM_TEXT_RECT] = new Vector4(textBox.Left, textBox.Top, textBox.Width, textBox.Height); DoRender(finalTransform); // Because text wraps around before it is complete scrolled off the screen we may need to render a second copy // to create the desired wrapping effect if (scrollMode != TextScrollEnum.None) { if (!float.IsNaN(_scrollWrapOffset.X)) { _effect.Parameters[PARAM_SCROLL_POSITION] = new Vector4(_scrollPos.X + _scrollWrapOffset.X, _scrollPos.Y, 0.0f, 0.0f); DoRender(finalTransform); } else if (!float.IsNaN(_scrollWrapOffset.Y)) { _effect.Parameters[PARAM_SCROLL_POSITION] = new Vector4(_scrollPos.X, _scrollPos.Y + _scrollWrapOffset.Y, 0.0f, 0.0f); DoRender(finalTransform); } } _lastTimeUsed = SkinContext.FrameRenderingStartTime; }
/// <summary> /// Simplified render method to draw the text with a given text offset. This can be used for text edit controls where the text is /// shifted horizontally against its textbox. /// </summary> /// <param name="textBox">The box where the text should be drawn.</param> /// <param name="horzAlignment">The horizontal alignment.</param> /// <param name="vertAlignment">The vertical alignment.</param> /// <param name="offsetX">Horizontal offset of the text in relation to its text box. A negative offset will make the text start left of its /// normal position.</param> /// <param name="color">The color.</param> /// <param name="zOrder">A value indicating the depth (and thus position in the visual heirachy) that this element should be rendered at.</param> /// <param name="finalTransform">The final combined layout/render-transform.</param> public void Render(RectangleF textBox, HorizontalTextAlignEnum horzAlignment, VerticalTextAlignEnum vertAlignment, float offsetX, Color4 color, float zOrder, Matrix finalTransform) { if (!IsAllocated || _lastWrap || _textChanged) { Allocate(textBox.Width, false); if (!IsAllocated) { return; } } // Prepare horizontal alignment info for shader. X is position offset, Y is multiplyer for line width. Vector4 alignParam; switch (horzAlignment) { case HorizontalTextAlignEnum.Center: alignParam = new Vector4(textBox.Width / 2.0f, -0.5f, zOrder, 1.0f); break; case HorizontalTextAlignEnum.Right: alignParam = new Vector4(textBox.Width, -1.0f, zOrder, 1.0f); break; //case TextAlignEnum.Left: default: alignParam = new Vector4(0.0f, 0.0f, zOrder, 1.0f); break; } // Do vertical alignment by adjusting yPosition float yPosition = 0.0f; switch (vertAlignment) { case VerticalTextAlignEnum.Bottom: yPosition = Math.Max(textBox.Height - _lastTextSize.Height, 0.0f); break; case VerticalTextAlignEnum.Center: yPosition += Math.Max((textBox.Height - _lastTextSize.Height) / 2.0f, 0.0f); break; //case TextAlignEnum.Top: // Do nothing } // No fading _effect = ContentManager.Instance.GetEffect(EFFECT_FONT); // Render _effect.Parameters[PARAM_COLOR] = color; _effect.Parameters[PARAM_ALIGNMENT] = alignParam; _effect.Parameters[PARAM_SCROLL_POSITION] = new Vector4(offsetX, yPosition, 0.0f, 0.0f); _effect.Parameters[PARAM_TEXT_RECT] = new Vector4(textBox.Left, textBox.Top, textBox.Width, textBox.Height); DoRender(finalTransform); _lastTimeUsed = SkinContext.FrameRenderingStartTime; }
/// <summary> /// Standard draw method for this text. /// </summary> /// <param name="textBox">The box where the text should be drawn.</param> /// <param name="horzAlignment">The horizontal alignment.</param> /// <param name="vertAlignment">The vertical alignment.</param> /// <param name="color">The color.</param> /// <param name="wrap">If <c>true</c> then text will be word-wrapped to fit the <paramref name="textBox"/>.</param> /// <param name="fade">If <c>true</c> then text will be faded at the edge of the <paramref name="textBox"/>.</param> /// <param name="zOrder">A value indicating the depth (and thus position in the visual heirachy) that this element should be rendered at.</param> /// <param name="scrollMode">Text scrolling behaviour.</param> /// <param name="scrollSpeed">Text scrolling speed in units (pixels at original skin size) per second.</param> /// <param name="scrollDelay">Text scrolling delay in seconds.</param> /// <param name="finalTransform">The final combined layout/render-transform.</param> public void Render(RectangleF textBox, HorizontalTextAlignEnum horzAlignment, VerticalTextAlignEnum vertAlignment, Color4 color, bool wrap, bool fade, float zOrder, TextScrollEnum scrollMode, float scrollSpeed, float scrollDelay, Matrix finalTransform) { if (!IsAllocated || wrap != _lastWrap || _textChanged || (wrap && textBox.Width != _lastTextBoxWidth)) { Allocate(textBox.Width, wrap); if (!IsAllocated) { return; } } // Update scrolling TextScrollEnum actualScrollMode = scrollMode; if (scrollMode != TextScrollEnum.None && _lastTimeUsed != DateTime.MinValue) { actualScrollMode = UpdateScrollPosition(textBox, scrollMode, scrollSpeed, scrollDelay); } // Prepare horizontal alignment info for shader. X is position offset, Y is multiplyer for line width. Vector4 alignParam; switch (horzAlignment) { case HorizontalTextAlignEnum.Center: alignParam = new Vector4(textBox.Width / 2.0f, -0.5f, zOrder, 1.0f); break; case HorizontalTextAlignEnum.Right: alignParam = new Vector4(textBox.Width, -1.0f, zOrder, 1.0f); break; //case TextAlignEnum.Left: default: alignParam = new Vector4(0.0f, 0.0f, zOrder, 1.0f); break; } // Do vertical alignment by adjusting yPosition float yPosition = 0.0f; switch (vertAlignment) { case VerticalTextAlignEnum.Bottom: yPosition = Math.Max(textBox.Height - _lastTextSize.Height, 0.0f); break; case VerticalTextAlignEnum.Center: yPosition += Math.Max((textBox.Height - _lastTextSize.Height) / 2.0f, 0.0f); break; //case TextAlignEnum.Top: // Do nothing } // Do we need to add fading edges? Vector4 fadeBorder; if (fade && CalculateFadeBorder(actualScrollMode, textBox, horzAlignment, out fadeBorder)) { _effect = ContentManager.Instance.GetEffect(EFFECT_FONT_FADE); _effect.Parameters[PARAM_FADE_BORDER] = fadeBorder; } else { _effect = ContentManager.Instance.GetEffect(EFFECT_FONT); } // Render _effect.Parameters[PARAM_COLOR] = color; _effect.Parameters[PARAM_ALIGNMENT] = alignParam; _effect.Parameters[PARAM_SCROLL_POSITION] = new Vector4(_scrollPos.X, _scrollPos.Y + yPosition, 0.0f, 0.0f); _effect.Parameters[PARAM_TEXT_RECT] = new Vector4(textBox.Left, textBox.Top, textBox.Width, textBox.Height); DoRender(finalTransform); // Because text wraps around before it is complete scrolled off the screen we may need to render a second copy // to create the desired wrapping effect if (scrollMode != TextScrollEnum.None) { if (!float.IsNaN(_scrollWrapOffset.X)) { _effect.Parameters[PARAM_SCROLL_POSITION] = new Vector4(_scrollPos.X + _scrollWrapOffset.X, _scrollPos.Y, 0.0f, 0.0f); DoRender(finalTransform); } else if (!float.IsNaN(_scrollWrapOffset.Y)) { _effect.Parameters[PARAM_SCROLL_POSITION] = new Vector4(_scrollPos.X, _scrollPos.Y + _scrollWrapOffset.Y, 0.0f, 0.0f); DoRender(finalTransform); } } _lastTimeUsed = SkinContext.FrameRenderingStartTime; }
public void DrawOverlay(Texture targetTexture) { Subtitle currentSubtitle; lock (_syncObj) { currentSubtitle = _subtitles.ToList().FirstOrDefault(s => s.ShouldDraw); if (currentSubtitle == null) { return; } try { // TemporaryRenderTarget changes RenderTarget to texture and restores settings when done (Dispose) using (new TemporaryRenderTarget(targetTexture)) { // Check the target texture dimensions and adjust scaling and translation SurfaceDescription desc = targetTexture.GetLevelDescription(0); Matrix transform = Matrix.Identity; // Position subtitle and scale it to match video frame size, if required transform *= Matrix.Translation(currentSubtitle.HorizontalPosition, currentSubtitle.FirstScanLine, 0); if (currentSubtitle.ScreenWidth != desc.Width || currentSubtitle.ScreenHeight != desc.Height) { var factorW = (float)desc.Width / currentSubtitle.ScreenWidth; var factorH = (float)desc.Height / currentSubtitle.ScreenHeight; transform *= Matrix.Scaling(factorW, factorH, 1); } if (!string.IsNullOrWhiteSpace(currentSubtitle.Text)) { // TODO: this calculation works at the moment only in fullscreen mode. When using windowed mode, the text is off screen on bottom and not visible. // Calculate font size by the available target height divided by the number of teletext lines (25). float fontSize = (float)Math.Floor(desc.Height / 25f); if (_textBuffer == null) { _textBuffer = new TextBuffer(FontManager.DefaultFontFamily, fontSize); } _textBuffer.Text = currentSubtitle.Text; RectangleF rectangleF = new RectangleF(0, 0, desc.Width, desc.Height); HorizontalTextAlignEnum horzAlign = HorizontalTextAlignEnum.Center; VerticalTextAlignEnum vertAlign = VerticalTextAlignEnum.Top; // Render "glow" var offset = 1f; _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.Black, 0, transform * Matrix.Translation(-offset, 0f, 0)); _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.Black, 0, transform * Matrix.Translation(-offset, -offset, 0)); _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.Black, 0, transform * Matrix.Translation(0.0f, offset, 0)); _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.Black, 0, transform * Matrix.Translation(offset, offset, 0)); // Text _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.White, 0, transform); } else { using (TemporaryRenderState temporaryRenderState = new TemporaryRenderState()) { // No alpha test here, allow all values temporaryRenderState.SetTemporaryRenderState(RenderState.AlphaTestEnable, 0); // Use the SourceAlpha channel and InverseSourceAlpha for destination temporaryRenderState.SetTemporaryRenderState(RenderState.BlendOperation, (int)BlendOperation.Add); temporaryRenderState.SetTemporaryRenderState(RenderState.SourceBlend, (int)Blend.SourceAlpha); temporaryRenderState.SetTemporaryRenderState(RenderState.DestinationBlend, (int)Blend.InverseSourceAlpha); if (currentSubtitle.SubTexture != null && !currentSubtitle.SubTexture.IsDisposed) { _sprite.Begin(SpriteFlags.AlphaBlend); _sprite.Transform = transform; _sprite.Draw(currentSubtitle.SubTexture, SharpDX.Color.White); _sprite.End(); } } } } } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Debug("Error in DrawOverlay", ex); } _onTextureInvalidated?.Invoke(); } }
public void DrawOverlay(Texture targetTexture) { Subtitle currentSubtitle; lock (_syncObj) { currentSubtitle = _subtitles.ToList().FirstOrDefault(s => s.ShouldDraw); if (currentSubtitle == null) { return; } try { // TemporaryRenderTarget changes RenderTarget to texture and restores settings when done (Dispose) using (new TemporaryRenderTarget(targetTexture)) { Matrix transform = Matrix.Identity; // Position subtitle transform *= Matrix.Translation(currentSubtitle.HorizontalPosition, currentSubtitle.FirstScanLine, 0); if (!string.IsNullOrWhiteSpace(currentSubtitle.Text)) { // Calculate font size by the available target height divided by the number of teletext lines (25). float fontSize = (float)Math.Floor(SkinContext.WindowSize.Height / 25f); if (_textBuffer == null) { _textBuffer = new TextBuffer(FontManager.DefaultFontFamily, fontSize); } _textBuffer.Text = currentSubtitle.Text; RectangleF rectangleF = new RectangleF(0, 0, SkinContext.WindowSize.Width, SkinContext.WindowSize.Height); HorizontalTextAlignEnum horzAlign = HorizontalTextAlignEnum.Center; VerticalTextAlignEnum vertAlign = VerticalTextAlignEnum.Top; // Render "glow" var offset = 1f; _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.Black, 0, transform * Matrix.Translation(-offset, 0f, 0)); _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.Black, 0, transform * Matrix.Translation(-offset, -offset, 0)); _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.Black, 0, transform * Matrix.Translation(0.0f, offset, 0)); _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.Black, 0, transform * Matrix.Translation(offset, offset, 0)); // Text _textBuffer.Render(rectangleF, horzAlign, vertAlign, 0, Color4.White, 0, transform); } else { using (TemporaryRenderState temporaryRenderState = new TemporaryRenderState()) { // No alpha test here, allow all values temporaryRenderState.SetTemporaryRenderState(RenderState.AlphaTestEnable, 0); // Use the SourceAlpha channel and InverseSourceAlpha for destination temporaryRenderState.SetTemporaryRenderState(RenderState.BlendOperation, (int)BlendOperation.Add); temporaryRenderState.SetTemporaryRenderState(RenderState.SourceBlend, (int)Blend.SourceAlpha); temporaryRenderState.SetTemporaryRenderState(RenderState.DestinationBlend, (int)Blend.InverseSourceAlpha); if (currentSubtitle.SubTexture != null && !currentSubtitle.SubTexture.IsDisposed) { _sprite.Begin(SpriteFlags.AlphaBlend); _sprite.Transform = transform; _sprite.Draw(currentSubtitle.SubTexture, SharpDX.Color.White); _sprite.End(); } } } } } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Debug("Error in DrawOverlay", ex); } _onTextureInvalidated?.Invoke(); } }