/// <summary> /// Append a text mesh to this drawlist /// </summary> public void AddText(Rect rect, string text, GUIState state) { //AddTextDrawCommand(); var textMesh = this.TextMesh; var oldIndexBufferCount = textMesh.IndexBuffer.Count; string fontFamily = ""; double fontSize = 18; Color fontColor = Color.Red; // get offset and scale from text layout var scale = OSImplentation.TypographyTextContext.GetScale(fontFamily, fontSize); var textContext = TextMeshUtil.GetTextContext(text, rect.Size, style, state) as OSImplentation.TypographyTextContext; var glyphOffsets = textContext.GlyphOffsets; int index = -1; // get glyph data from typeface FontStyle fontStyle = style.FontStyle; FontWeight fontWeight = style.FontWeight; foreach (var character in text) { index++; if (char.IsWhiteSpace(character)) { continue; } var glyphData = GlyphCache.Default.GetGlyph(character, fontFamily, fontStyle, fontWeight); if (glyphData == null) { Typography.OpenFont.Glyph glyph = OSImplentation.TypographyTextContext.LookUpGlyph(fontFamily, character); var polygons = new List <List <Point> >(); var bezierSegments = new List <(Point, Point, Point)>(); Typography.OpenFont.GlyphLoader.Read(glyph, out polygons, out bezierSegments); GlyphCache.Default.AddGlyph(character, fontFamily, fontStyle, fontWeight, polygons, bezierSegments); glyphData = GlyphCache.Default.GetGlyph(character, fontFamily, fontStyle, fontWeight); Debug.Assert(glyphData != null); } // append to drawlist Vector glyphOffset = glyphOffsets[index]; var positionOffset = (Vector)rect.TopLeft; this.TextMesh.Append(positionOffset, glyphData, glyphOffset, scale, fontColor, false); } var newIndexBufferCount = textMesh.IndexBuffer.Count; // Update command var command = textMesh.Commands[textMesh.Commands.Count - 1]; command.ElemCount += newIndexBufferCount - oldIndexBufferCount; textMesh.Commands[textMesh.Commands.Count - 1] = command; // TODO refactor this }
public Glyph(Typography.OpenFont.Typeface typeface, Typography.OpenFont.Glyph info) { Typeface = typeface ?? throw new System.ArgumentNullException(nameof(typeface)); Info = info ?? throw new System.ArgumentNullException(nameof(info)); }
public void Deconstruct (out Typography.OpenFont.Typeface typeface, out Typography.OpenFont.Glyph glyph) { typeface = Typeface; glyph = Info; }
/// <summary> /// Draw a text primitive and merge the result to the text mesh. /// </summary> /// <param name="primitive"></param> /// <param name="fontFamily">font file path</param> /// <param name="fontSize">font pixel size</param> /// <param name="fontColor">font color</param> /// <param name="fontStyle">italic or normal. Oblique will not be supported for now.</param> /// <param name="fontWeight">bold or normal.</param> /// TODO apply text alignment public void DrawText(TextPrimitive primitive, Rect rect, string fontFamily, double fontSize, Color fontColor, FontStyle fontStyle, FontWeight fontWeight) { primitive.Offset = (Vector)rect.TopLeft; //check if we need to rebuild the glyph data of this text primitive var needRebuild = this.CheckTextPrimitive(primitive, fontFamily, fontSize, fontStyle, fontWeight); //build text mesh if (needRebuild) { primitive.FontFamily = fontFamily; // primitive.FontSize = fontSize; primitive.FontStyle = fontStyle; //No effect in current Typography. primitive.FontWeight = fontWeight; //No effect in current Typography. var textContext = new OSImplentation.TypographyTextContext(primitive.Text, fontFamily, (float)fontSize, FontStretch.Normal, fontStyle, fontWeight, (int)rect.Size.Width, (int)rect.Size.Height, TextAlignment.Leading); textContext.Build((Point)primitive.Offset); primitive.Offsets.AddRange(textContext.GlyphOffsets); foreach (var character in primitive.Text) { if (char.IsWhiteSpace(character)) { continue; } Typography.OpenFont.Glyph glyph = OSImplentation.TypographyTextContext.LookUpGlyph(fontFamily, character); Typography.OpenFont.GlyphLoader.Read(glyph, out var polygons, out var bezierSegments); var glyphData = GlyphCache.Default.GetGlyph(character, fontFamily, fontStyle, fontWeight); if (glyphData == null) { glyphData = GlyphCache.Default.AddGlyph(character, fontFamily, fontStyle, fontWeight, polygons, bezierSegments); } Debug.Assert(glyphData != null); primitive.Glyphs.Add(glyphData); } } //FIXME Should each text segment consume a draw call? NO! //add a new draw command DrawCommand cmd = new DrawCommand(); cmd.ClipRect = Rect.Big; cmd.TextureData = null; this.TextMesh.Commands.Add(cmd); var oldIndexBufferCount = this.TextMesh.IndexBuffer.Count; var scale = OSImplentation.TypographyTextContext.GetScale(fontFamily, fontSize); int index = -1; // get glyph data from typeface foreach (var character in primitive.Text) { if (char.IsWhiteSpace(character)) { continue; } index++; var glyphData = primitive.Glyphs[index]; Vector glyphOffset = primitive.Offsets[index]; this.TextMesh.Append(primitive.Offset, glyphData, glyphOffset, scale, fontColor, false); } var newIndexBufferCount = this.TextMesh.IndexBuffer.Count; // Update command var command = this.TextMesh.Commands[this.TextMesh.Commands.Count - 1]; command.ElemCount += newIndexBufferCount - oldIndexBufferCount; this.TextMesh.Commands[this.TextMesh.Commands.Count - 1] = command; }
/// <summary> /// Draw a text primitive and merge the result to the text mesh. /// </summary> /// <param name="primitive"></param> /// <param name="rect"></param> /// <param name="style"></param> public void DrawText(TextPrimitive primitive, Rect rect, StyleRuleSet style) { //check if we need to rebuild the glyph data of this text primitive var needRebuild = this.CheckTextPrimitive(primitive, style); var fontFamily = style.FontFamily; var fontSize = style.FontSize; var fontColor = style.FontColor; //build text mesh if (needRebuild) { primitive.Glyphs.Clear(); primitive.Offsets.Clear(); primitive.FontSize = fontSize; primitive.FontFamily = fontFamily; primitive.FontStyle = style.FontStyle; primitive.FontWeight = style.FontWeight; var fontStretch = FontStretch.Normal; var fontStyle = style.FontStyle; var fontWeight = style.FontWeight; var textAlignment = (TextAlignment)style.Get <int>(GUIStyleName.TextAlignment);//TODO apply text alignment var textContext = new OSImplentation.TypographyTextContext(primitive.Text, fontFamily, fontSize, fontStretch, fontStyle, fontWeight, (int)rect.Size.Width, (int)rect.Size.Height, textAlignment); textContext.Build(rect.Location); primitive.Offsets.AddRange(textContext.GlyphOffsets); foreach (var character in primitive.Text) { Typography.OpenFont.Glyph glyph = OSImplentation.TypographyTextContext.LookUpGlyph(fontFamily, character); Typography.OpenFont.GlyphLoader.Read(glyph, out var polygons, out var bezierSegments); var glyphData = GlyphCache.Default.GetGlyph(character, fontFamily, fontStyle, fontWeight); if (glyphData == null) { glyphData = GlyphCache.Default.AddGlyph(character, fontFamily, fontStyle, fontWeight, polygons, bezierSegments); } Debug.Assert(glyphData != null); primitive.Glyphs.Add(glyphData); } } //FIXME Should each text segment consume a draw call? NO! //add a new draw command DrawCommand cmd = new DrawCommand(); cmd.ClipRect = Rect.Big; cmd.TextureData = null; this.TextMesh.Commands.Add(cmd); var oldIndexBufferCount = this.TextMesh.IndexBuffer.Count; var scale = OSImplentation.TypographyTextContext.GetScale(fontFamily, fontSize); int index = -1; // get glyph data from typeface foreach (var character in primitive.Text) { index++; var glyphData = primitive.Glyphs[index]; Vector glyphOffset = primitive.Offsets[index]; this.TextMesh.Append((Vector)rect.Location + primitive.Offset, glyphData, glyphOffset, scale, fontColor, false); } var newIndexBufferCount = this.TextMesh.IndexBuffer.Count; // Update command var command = this.TextMesh.Commands[this.TextMesh.Commands.Count - 1]; command.ElemCount += newIndexBufferCount - oldIndexBufferCount; this.TextMesh.Commands[this.TextMesh.Commands.Count - 1] = command; }
private void cmdMeasureTextSpan_Click(object sender, System.EventArgs e) { //set some Gdi+ props... g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.Clear(Color.White); //credit: //http://stackoverflow.com/questions/1485745/flip-coordinates-when-drawing-to-control g.ScaleTransform(1.0F, -1.0F); // Flip the Y-Axis g.TranslateTransform(0.0F, -(float)300); // Translate the drawing area accordingly //-------------------------------- //textspan measurement sample //-------------------------------- _currentTextPrinter.HintTechnique = (HintTechnique)lstHintList.SelectedItem; _currentTextPrinter.PositionTechnique = (PositionTechnique)cmbPositionTech.SelectedItem; //render at specific pos float x_pos = 0, y_pos = 100; char[] textBuffer = txtInputChar.Text.ToCharArray(); //Example 1: this is a basic draw sample _currentTextPrinter.FillColor = Color.Black; _currentTextPrinter.TargetGraphics = g; _currentTextPrinter.DrawString( textBuffer, 0, textBuffer.Length, x_pos, y_pos ); // //-------------------------------------------------- //Example 2: print glyph plan to 'user' list-> then draw it (or hold it/ not draw) //you can create you own class to hold userGlyphPlans.*** //2.1 _reusableUnscaledGlyphPlanList.Clear(); _currentTextPrinter.GenerateGlyphPlan(textBuffer, 0, textBuffer.Length, _reusableUnscaledGlyphPlanList); //2.2 //and we can print the formatted glyph plan later. y_pos -= _currentTextPrinter.FontLineSpacingPx; _currentTextPrinter.FillColor = Color.Red; _currentTextPrinter.DrawFromGlyphPlans( new GlyphPlanSequence(_reusableUnscaledGlyphPlanList), x_pos, y_pos ); //Example 3: MeasureString Typography.OpenFont.Typeface typeface = _currentTextPrinter.Typeface; UnscaledGlyphPlanList userGlyphPlans = new UnscaledGlyphPlanList(); _currentTextPrinter.GlyphLayoutMan.GenerateUnscaledGlyphPlans(userGlyphPlans); MeasuredStringBox strBox = new MeasuredStringBox(); throw new System.NotSupportedException(); //_currentTextPrinter.GlyphLayoutMan.LayoutAndMeasureString( // textBuffer, 0, textBuffer.Length, // _currentTextPrinter.FontSizeInPoints, // true, // userGlyphPlans); float x_pos2 = x_pos + strBox.width + 10; g.DrawRectangle(Pens.Red, x_pos, y_pos + strBox.descending, strBox.width, strBox.CalculateLineHeight()); g.DrawLine(Pens.Blue, x_pos, y_pos, x_pos2, y_pos); //baseline g.DrawLine(Pens.Green, x_pos, y_pos + strBox.descending, x_pos2, y_pos + strBox.descending); //descending g.DrawLine(Pens.Magenta, x_pos, y_pos + strBox.ascending, x_pos2, y_pos + strBox.ascending); //ascending Typography.OpenFont.TypefaceExtension2.UpdateAllCffGlyphBounds(typeface); float pxscale = typeface.CalculateScaleToPixelFromPointSize(_currentTextPrinter.FontSizeInPoints); int j = userGlyphPlans.Count; for (int i = 0; i < j; ++i) { UnscaledGlyphPlan glyphPlan = userGlyphPlans[i]; Typography.OpenFont.Glyph glyph = typeface.GetGlyphByIndex(glyphPlan.glyphIndex); // Typography.OpenFont.Bounds b = glyph.Bounds; // float xmin = b.XMin * pxscale; float ymin = b.YMin * pxscale; // float xmax = b.XMax * pxscale; float ymax = b.YMax * pxscale; // float glyph_x = x_pos + glyphPlan.OffsetX; g.DrawRectangle(Pens.Red, glyph_x + xmin, y_pos + ymin, xmax - xmin, ymax - ymin); } //------------ _currentTextPrinter.FillColor = Color.Black; //transform back g.ScaleTransform(1.0F, -1.0F); // Flip the Y-Axis g.TranslateTransform(0.0F, -(float)300); // Translate the drawing area accordingly }