/// <summary>Construct an instance.</summary> /// <param name="label">A short field label.</param> /// <param name="value">The field value.</param> /// <param name="hasValue">Whether the field should be displayed (or <c>null</c> to check the <paramref name="value"/>).</param> public GenericField(string label, IFormattedText value, bool?hasValue = null) : this(label, new[] { value }, hasValue) { }
public void DrawText(IFormattedText formattedText, Matrix transform, DrawOptions drawOptions) { if (!(formattedText is FormattedText)) { throw new ArgumentException("Argument formattedText is not an object returned by FormatText() method."); } PInvokes.D3d9.BeginPixEvent(0, "DrawText: " + formattedText.Text); var typedFormattedText = (FormattedText)formattedText; if ((typedFormattedText.RichTextFormat || typedFormattedText.m_lines.Length > 1 || typedFormattedText.FormatOptions.Alignment != Alignment.LeftTop) && (drawOptions.SubstringStart != 0 || drawOptions.SubstringLength != -1 || drawOptions.BaseIndex != 0)) { throw new InvalidOperationException("Drawing substring can only be performed on non-RTF text."); } var globalOffset = Vector2.Zero; globalOffset.X = typedFormattedText.Offset.X + drawOptions.Offset.X; globalOffset.Y = typedFormattedText.Offset.Y + drawOptions.Offset.Y; if ((drawOptions.DrawFlags & DrawFlags.OffsetByHalfPixel) != 0) { globalOffset += new Vector2(-0.5f, -0.5f); } List<PositionedGlyphPage> glyphPages = new List<PositionedGlyphPage>(); foreach (var line in typedFormattedText.m_lines) { for (int i = 0; i < (drawOptions.SubstringLength == -1 ? line.m_glyphs.Length : drawOptions.SubstringLength); ++i) { var glyph = line.m_glyphs[i + drawOptions.SubstringStart]; if (IsWhitespaceChar(glyph.m_glyph)) { continue; } var glyphData = Load(glyph.m_glyph, typedFormattedText.FormatOptions); var pagesInX = glyphData.m_pageIndices.GetUpperBound(0); var pagesInY = glyphData.m_pageIndices.GetUpperBound(1); for (int x = 0; x <= pagesInX; ++x) { for (int y = 0; y <= pagesInY; ++y) { var glyphPos = glyph.m_pos + line.m_offset + globalOffset; glyphPos.X -= line.m_glyphs[drawOptions.BaseIndex].m_pos.X; glyphPages.Add(new PositionedGlyphPage { m_pos = glyphPos + new Vector2(x * PageSize, y * PageSize), m_color = drawOptions.ForcedColor == Color.Transparent ? glyph.m_color : drawOptions.ForcedColor, m_hasOutline = IsAnsiChar(glyph.m_glyph) ? formattedText.FormatOptions.AnsiFont.OutlineThickness > 0 : formattedText.FormatOptions.Font.OutlineThickness > 0, m_pageIndex = glyphData.m_pageIndices[x, y] }); } } } } Func<PositionedGlyphPage, int> batchCriteria = page => page.m_pageIndex / PagesInOneCacheTexture / 4; bool useBoundingBox = (drawOptions.DrawFlags & DrawFlags.BoundedByBox) != 0; int counter = 0; var device = GameApp.Instance.GraphicsDevice; device.Indices = null; device.BlendState = BlendState.AlphaBlend; device.DepthStencilState = DepthStencilState.None; device.RasterizerState = RasterizerState.CullCounterClockwise; m_effect.CurrentTechnique = m_techDraw; if ((drawOptions.DrawFlags & DrawFlags.TransformToClipSpace) != 0) { var mtx = Matrix.Identity; mtx.M11 = 2.0f / device.Viewport.Width; mtx.M22 = -2.0f / device.Viewport.Height; mtx.M41 = -1.0f; mtx.M42 = 1.0f; transform = mtx * transform; } m_paramWorldViewProj.SetValue(transform); m_paramPageSize.SetValue(new Vector2(PageSize, PageSize)); m_paramPageUVSize.SetValue(new Vector2((float)PageSize / CacheTextureSize, (float)PageSize / CacheTextureSize)); m_paramTextureSize.SetValue(new Vector2(CacheTextureSize, CacheTextureSize)); m_paramInvTextureSize.SetValue(new Vector2(1.0f / CacheTextureSize, 1.0f / CacheTextureSize)); m_paramNumPages.SetValue(new Vector2(PagesInOneRow, RowsInOneCacheTexture)); m_paramInvNumPages.SetValue(new Vector2(1.0f / PagesInOneRow, 1.0f / RowsInOneCacheTexture)); var premultipliedColorScaling = drawOptions.ColorScaling; premultipliedColorScaling.X *= premultipliedColorScaling.W; premultipliedColorScaling.Y *= premultipliedColorScaling.W; premultipliedColorScaling.Z *= premultipliedColorScaling.W; m_paramColorScaling.SetValue(premultipliedColorScaling); var premultipliedOutlineColor = drawOptions.OutlineColor; premultipliedOutlineColor.X *= premultipliedOutlineColor.W; premultipliedOutlineColor.Y *= premultipliedOutlineColor.W; premultipliedOutlineColor.Z *= premultipliedOutlineColor.W; m_paramOutlineColor.SetValue(premultipliedOutlineColor); var vertices = new VertexDataDraw[glyphPages.Count * 6]; foreach (var batch in glyphPages.GroupBy(batchCriteria)) { Texture2D texture = m_cacheTextures[batch.Key * 4].m_physicalRTTexture; m_paramTexture.SetValue(texture); var arrayStart = counter; foreach (var glyphPage in batch) { float boundedLeft, boundedTop, boundedWidth, boundedHeight; if (useBoundingBox) { boundedLeft = (drawOptions.BoundingBox.Left - glyphPage.m_pos.X) / PageSize; boundedTop = (drawOptions.BoundingBox.Top - glyphPage.m_pos.Y) / PageSize; boundedWidth = (drawOptions.BoundingBox.Right - glyphPage.m_pos.X) / PageSize; boundedHeight = (drawOptions.BoundingBox.Bottom - glyphPage.m_pos.Y) / PageSize; if (boundedLeft >= 1.0f || boundedTop >= 1.0f || boundedWidth <= 0.0f || boundedHeight <= 0.0f) { continue; } boundedLeft = Math.Max(boundedLeft, 0.0f); boundedTop = Math.Max(boundedTop, 0.0f); boundedWidth = Math.Min(boundedWidth, 1.0f); boundedHeight = Math.Min(boundedHeight, 1.0f); } else { boundedLeft = boundedTop = 0; boundedWidth = boundedHeight = 1; } var localPageIndex = glyphPage.m_pageIndex % PagesInOneCacheTexture; var pageX = localPageIndex % PagesInOneRow; var pageY = localPageIndex / PagesInOneRow; int channel = glyphPage.m_pageIndex / PagesInOneCacheTexture % 4; for (int i = 0; i < 6; ++i) { vertices[counter + i].m_leftTopPos.X = glyphPage.m_pos.X; vertices[counter + i].m_leftTopPos.Y = glyphPage.m_pos.Y; vertices[counter + i].m_localPageXY_mask = new Byte4(pageX, pageY, channel, glyphPage.m_hasOutline ? 1 : 0); vertices[counter + i].m_color = glyphPage.m_color; } vertices[counter + 0].m_corner = new Short2N(boundedLeft, boundedTop); vertices[counter + 1].m_corner = vertices[counter + 4].m_corner = new Short2N(boundedWidth, boundedTop); vertices[counter + 2].m_corner = vertices[counter + 3].m_corner = new Short2N(boundedLeft, boundedHeight); vertices[counter + 5].m_corner = new Short2N(boundedWidth, boundedHeight); counter += 6; } if (counter == 0) { break; } var batchSize = counter - arrayStart; var bufferOffset = CopyInstanceVertices(vertices, arrayStart, batchSize); device.SetVertexBuffer(m_verticesDraw); foreach (var pass in m_techDraw.Passes) { pass.Apply(); device.DrawPrimitives(PrimitiveType.TriangleList, bufferOffset, counter / 3); } } PInvokes.D3d9.EndPixEvent(); }
/// <summary>Construct an instance.</summary> /// <param name="gameHelper">Provides utility methods for interacting with the game code.</param> /// <param name="label">A short field label.</param> /// <param name="value">The field value.</param> /// <param name="hasValue">Whether the field should be displayed (or <c>null</c> to check the <paramref name="value"/>).</param> public GenericField(GameHelper gameHelper, string label, IFormattedText value, bool?hasValue = null) : this(gameHelper, label, new[] { value }, hasValue) { }
public void DrawText(IFormattedText formattedText, Matrix transform) { DrawText(formattedText, transform, DrawOptions.Default); }