public void AddTask(string s, Font font, Brush brush, PointF point) { if (!(brush is SolidBrush)) { throw new NotSupportedException("brush"); } _colors.Add((brush as SolidBrush).Color); MyFont myFont = FontManager.GetFont(FontManager.FindClosestFont(font)); string[] lines = s.Split('\n'); float k = (font.SizeInPoints / myFont.FontInfo.Pt); //k = 1; int glyphHeight = (int)(k * myFont.FontInfo.Height); int realStrLen = 0; foreach (string str in lines) { int strLen = str.Length; realStrLen += strLen; float x = point.X; for (int j = 0; j < strLen; j++) { if (!myFont.Symbols.ContainsKey(str[j])) { realStrLen--; continue; } GlyphData symbol = myFont.Symbols[str[j]]; AddVertex(x + symbol.XOffset * k, point.Y + symbol.YOffset * k, symbol.TextureXPos, symbol.TextureYPos); AddVertex(x + (symbol.XOffset + symbol.Width) * k, point.Y + symbol.YOffset * k, symbol.TextureWidth, symbol.TextureYPos); AddVertex(x + symbol.XOffset * k, point.Y + (symbol.YOffset + symbol.Height) * k, symbol.TextureXPos, symbol.TextureHeight); AddVertex(x + (symbol.XOffset + symbol.Width) * k, point.Y + symbol.YOffset * k, symbol.TextureWidth, symbol.TextureYPos); AddVertex(x + (symbol.XOffset + symbol.Width) * k, point.Y + (symbol.YOffset + symbol.Height) * k, symbol.TextureWidth, symbol.TextureHeight); AddVertex(x + symbol.XOffset * k, point.Y + (symbol.YOffset + symbol.Height) * k, symbol.TextureXPos, symbol.TextureHeight); x += (myFont.Symbols[str[j]].OrigW + (j != strLen - 1 ? myFont.GetKerningDelta(str[j], str[j + 1]) : 0.0f)) * k; } point.Y += glyphHeight; } _stringLens.Add(realStrLen); _fontTextures.Add(myFont.FontTexture); }
private void ProcessTextAdv(string text, int index, out GlyphData glyphData, out Rect uvRect, out float glyphXAdv, out float glyphXOff, out float glyphYOff) { char glyph = text[index]; int charIndex = (int)glyph > this.charLookup.Length ? 0 : this.charLookup[(int)glyph]; this.texture.LookupAtlas(charIndex, out uvRect); this.GetGlyphData(glyph, out glyphData); glyphXOff = -glyphData.OffsetX; glyphYOff = -glyphData.OffsetY; if (this.kerning && !this.monospace) { char glyphNext = index + 1 < text.Length ? text[index + 1] : ' '; GlyphData glyphDataNext; this.GetGlyphData(glyphNext, out glyphDataNext); int minSum = int.MaxValue; for (int k = 0; k < glyphData.KerningSamplesRight.Length; k++) { minSum = Math.Min(minSum, glyphData.KerningSamplesRight[k] + glyphDataNext.KerningSamplesLeft[k]); } glyphXAdv = glyphData.Width - glyphData.OffsetX + this.spacing - minSum; } else { glyphXAdv = (this.monospace ? this.maxGlyphWidth : (glyphData.Width - glyphData.OffsetX)) + this.spacing; } }
public string Serialize1(GlyphData glyphData) { StringWriter sw = new StringWriter(); JsonTextWriter writer = new JsonTextWriter(sw); writer.WriteStartObject(); if (glyphData.FormDefinitionKey.HasValue) { writer.WritePropertyName("FormDefinitionKey"); writer.WriteValue(glyphData.FormDefinitionKey); } if (glyphData.CorrelationKey.HasValue) { writer.WritePropertyName("CorrelationKey"); writer.WriteValue(glyphData.CorrelationKey); } writer.WritePropertyName("PageNumber"); writer.WriteValue(glyphData.PageNumber); writer.WriteEndObject(); return(sw.ToString()); }
public GlyphData AddUniqueGlyph(ushort glyph, float width) { GlyphData glyphData = new GlyphData(glyph, width); if (this.UniqueGlyphs.BinarySearch(glyphData) >= 0) { return(null); } int num = 0; while (num < this.UniqueGlyphs.Count) { if (glyphData.Glyph >= this.UniqueGlyphs[num].Glyph) { num++; continue; } this.UniqueGlyphs.Insert(num, glyphData); break; } if (num == this.UniqueGlyphs.Count) { this.UniqueGlyphs.Add(glyphData); } return(glyphData); }
/** * Build vertical metrics with Identity CIDToGIDMap (for embedding full font). */ private void BuildVerticalMetrics(PdfDictionary cidFont) { if (!BuildVerticalHeader(cidFont)) { return; } int cidMax = ttf.NumberOfGlyphs; int[] gidMetrics = new int[cidMax * 4]; for (int cid = 0; cid < cidMax; cid++) { GlyphData glyph = ttf.Glyph.GetGlyph(cid); if (glyph == null) { gidMetrics[cid * 4] = int.MinValue; } else { gidMetrics[cid * 4] = cid; gidMetrics[cid * 4 + 1] = ttf.VerticalMetrics.GetAdvanceHeight(cid); gidMetrics[cid * 4 + 2] = ttf.HorizontalMetrics.GetAdvanceWidth(cid); gidMetrics[cid * 4 + 3] = glyph.YMaximum + ttf.VerticalMetrics.GetTopSideBearing(cid); } } cidFont[PdfName.W2] = GetVerticalMetrics(gidMetrics); }
public override void Execute(ref GlyphShaderContext context, ref GlyphData data, int index) { var timeoffset = (Int32)(DateTime.UtcNow.TimeOfDay.TotalMilliseconds / 25); // number here is speed var angle = ((timeoffset + index) / 60.0) * Math.PI * 2.0; // change for x scale data.Y += (Single)Math.Sin(angle) * 10f; // number there is y scale }
internal void AddSymbol(char symbol, GlyphData glyphData) { if (Symbols.ContainsKey(symbol)) { return; } Symbols.Add(symbol, glyphData); }
/** * Builds vertical metrics with a custom CIDToGIDMap (for embedding font subset). */ private void BuildVerticalMetrics(Dictionary <int, int> cidToGid) { // The "vhea" and "vmtx" tables that specify vertical metrics shall never be used by a conforming // reader. The only way to specify vertical metrics in PDF shall be by means of the DW2 and W2 // entries in a CIDFont dictionary. if (!BuildVerticalHeader(cidFont)) { return; } float scaling = 1000f / ttf.Header.UnitsPerEm; VerticalHeaderTable vhea = ttf.VerticalHeader; VerticalMetricsTable vmtx = ttf.VerticalMetrics; GlyphTable glyf = ttf.Glyph; HorizontalMetricsTable hmtx = ttf.HorizontalMetrics; long v_y = (long)Math.Round(vhea.Ascender * scaling); long w1 = (long)Math.Round(-vhea.AdvanceHeightMax * scaling); PdfArray heights = new PdfArray(); PdfArray w2 = new PdfArray(); int prev = int.MinValue; // Use a sorted list to get an optimal width array ISet <int> keys = new HashSet <int>(cidToGid.Keys); foreach (int cid in keys) { // Unlike buildWidths, we look up with cid (not gid) here because this is // the original TTF, not the rebuilt one. GlyphData glyph = glyf.GetGlyph(cid); if (glyph == null) { continue; } long height = (long)Math.Round((glyph.YMaximum + vmtx.GetTopSideBearing(cid)) * scaling); long advance = (long)Math.Round(-vmtx.GetAdvanceHeight(cid) * scaling); if (height == v_y && advance == w1) { // skip default metrics continue; } // c [w1_1y v_1x v_1y w1_2y v_2x v_2y ... w1_ny v_nx v_ny] if (prev != cid - 1) { w2 = new PdfArray(); heights.Add(PdfInteger.Get(cid)); // c heights.Add(w2); } w2.Add(PdfInteger.Get(advance)); // w1_iy long width = (long)Math.Round(hmtx.GetAdvanceWidth(cid) * scaling); w2.Add(PdfInteger.Get(width / 2)); // v_ix w2.Add(PdfInteger.Get(height)); // v_iy prev = cid; } cidFont[PdfName.W2] = heights; }
public void Setup() { CompositeResolver.RegisterAndSetAsDefault(new IJsonFormatter[] { new GlyphDataFormatter() }, new[] { StandardResolver.Default }); _glyphSource = new GlyphData() { FormDefinitionKey = Guid.NewGuid(), PageNumber = 1 }; _jsonSource = (new JsonGlyphSerializer()).Serialize(_glyphSource); }
public GlyphData(GlyphData rhs) { info = rhs.info; width = rhs.width; height = rhs.height; scaleNeeded = rhs.scaleNeeded; // don't support copying bitmap stuff yet. System.Diagnostics.Debug.Assert(rhs.bmp == null); }
int IComparable.CompareTo(object o1) { GlyphData glyphData = (GlyphData)o1; if (Glyph < glyphData.Glyph) { return(-1); } if (Glyph > glyphData.Glyph) { return(1); } return(0); }
/// <summary> /// Retrieves information about a single glyph. /// </summary> /// <param name="glyph">The glyph to retrieve information about.</param> /// <param name="data">A struct holding the retrieved information.</param> /// <returns>True, if successful, false if the specified glyph is not supported.</returns> public bool GetGlyphData(char glyph, out GlyphData data) { int glyphId = (int)glyph; if (glyphId >= this.charLookup.Length) { data = this.glyphs[0]; return(false); } else { data = this.glyphs[this.charLookup[glyphId]]; return(true); } }
public GlyphData Deserialize1(string json) { Utf8JsonReader reader = new Utf8JsonReader(Encoding.ASCII.GetBytes(json)); GlyphData glyphData = null; while (reader.Read()) { switch (reader.TokenType) { case JsonTokenType.StartObject: glyphData = new GlyphData(); break; case JsonTokenType.PropertyName: { var value = reader.GetString(); reader.Read(); if (value.Equals("FormDefinitionKey")) { var s = reader.GetString(); if (s != null) { glyphData.FormDefinitionKey = Guid.Parse(s); } } else if (value.Equals("CorrelationKey")) { var v = reader.GetString(); if (v != null) { glyphData.CorrelationKey = Guid.Parse(v); } } else if (value.Equals("PageNumber")) { glyphData.PageNumber = reader.GetInt32(); } break; } case JsonTokenType.EndObject: return(glyphData); } } return(glyphData); }
public GlyphData Deserialize1(string json) { JsonTextReader reader = new JsonTextReader(new StringReader(json)); GlyphData glyphData = new GlyphData(); while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { switch (reader.Value) { case nameof(GlyphData.FormDefinitionKey): { var value = reader.ReadAsString(); if (value != null) { glyphData.FormDefinitionKey = Guid.Parse(value); } break; } case nameof(GlyphData.CorrelationKey): { var value = reader.ReadAsString(); if (value != null) { glyphData.CorrelationKey = Guid.Parse(value); } break; } case nameof(GlyphData.PageNumber): { var value = reader.ReadAsInt32(); if (value.HasValue) { glyphData.PageNumber = value.Value; } break; } } } } return(glyphData); }
/// <summary> /// Executes the glyph shader. /// </summary> /// <param name="context">The glyph shader contxt in which to execute the shader.</param> /// <param name="data">The data for the glyph which is being drawn.</param> /// <param name="index">The index of the glyph within its source string.</param> public void Execute(ref GlyphShaderContext context, ref GlyphData data, Int32 index) { if (glyphShaderScopedStack != null) { foreach (var shader in glyphShaderScopedStack) shader.Value.Execute(ref context, ref data, index); } else if (glyphShaderStack != null) { foreach (var shader in glyphShaderStack) shader.Execute(ref context, ref data, index); } else if (glyphShader != null) { glyphShader.Execute(ref context, ref data, index); } }
public void SetSnapshotAndUpdate(ITextSnapshot snapshot, IList <ITextViewLine> newOrReformattedLines, IList <ITextViewLine> translatedLines) { if (_glyphs.Count > 0) { // Go through all the existing visuals and invalidate or transform as appropriate. Dictionary <UIElement, GlyphData> newVisuals = new Dictionary <UIElement, GlyphData>(_glyphs.Count); foreach (var glyph in _glyphs) { GlyphData data = glyph.Value; if (!data.VisualSpan.HasValue) { newVisuals[glyph.Key] = data; } else { data.SetSnapshot(snapshot); SnapshotSpan span = data.VisualSpan.Value; if ((!_margin.TextView.TextViewLines.IntersectsBufferSpan(span)) || (GetStartingLine(newOrReformattedLines, span, returnLastLine: false) != null)) { //Either visual is no longer visible or it crosses a line //that was reformatted. _canvas.Children.Remove(data.Element); } else { newVisuals[data.Element] = data; ITextViewLine line = GetStartingLine(translatedLines, span, returnLastLine: true); if (line != null) { data.SetTop(line.Top - _margin.TextView.ViewportTop); } } } } _glyphs = newVisuals; } }
public GlyphData FromString(string glyph) { GlyphData glyphData = new GlyphData(); string[] glyphs = glyph.Split(';'); if (glyphs[0] != "") { glyphData.FormDefinitionKey = Guid.Parse(glyphs[0]); } if (glyphs[1] != "") { glyphData.CorrelationKey = Guid.Parse(glyphs[1]); } if (glyphs[2] != "") { glyphData.PageNumber = Int32.Parse(glyphs[2]); } return(glyphData); }
private GlyphData GetOrCreateGlyph(GlyphIndex glyphIndex) { // Try to find glyph in dictionary WeakReference <GlyphData> glyphDataRef; if (_glyphDictionary.TryGetValue(glyphIndex, out glyphDataRef)) { GlyphData glyphData; if (glyphDataRef.TryGetTarget(out glyphData)) { return(glyphData); } _glyphDictionary.Remove(glyphIndex); } // Add and return { GlyphData glyphData = GdiCreateGlyph(glyphIndex); _glyphDictionary.Add(glyphIndex, new WeakReference <GlyphData>(glyphData)); return(glyphData); } }
public void RemoveGlyphsByVisualSpan(SnapshotSpan span) { List <UIElement> glyphsInSpan = new List <UIElement>(); foreach (var glyph in _glyphs) { GlyphData data = glyph.Value; if (data.VisualSpan.HasValue) { if (span.IntersectsWith(data.VisualSpan.Value)) { glyphsInSpan.Add(glyph.Key); _canvas.Children.Remove(data.Element); } } } foreach (UIElement element in glyphsInSpan) { _glyphs.Remove(element); } }
public string Serialize1(GlyphData glyphData) { using var ms = new MemoryStream(); using var writer = new Utf8JsonWriter(ms); writer.WriteStartObject(); if (glyphData.FormDefinitionKey.HasValue) { writer.WriteString("FormDefinitionKey", glyphData.FormDefinitionKey.ToString()); } if (glyphData.CorrelationKey.HasValue) { writer.WriteString("CorrelationKey", glyphData.CorrelationKey.ToString()); } writer.WriteNumber("PageNumber", glyphData.PageNumber); writer.WriteEndObject(); writer.Flush(); return(Encoding.UTF8.GetString(ms.ToArray())); }
public void AddGlyph(string text, SnapshotSpan span) { IWpfTextViewLineCollection lines = _margin.TextView.TextViewLines; bool visible = _margin.TextView.TextViewLines.IntersectsBufferSpan(span); if (visible) { ITextViewLine line = GetStartingLine(lines, span, returnLastLine: true); if (line != null) { UIElement element = CreatePromptElement(text); element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); double leftPlacement = (17.0 - element.DesiredSize.Width) / 2; Canvas.SetLeft(element, leftPlacement); GlyphData data = new GlyphData(span, element); data.SetTop(line.TextTop - _margin.TextView.ViewportTop); _glyphs[element] = data; _canvas.Children.Add(element); } } }
internal GlyphData AddUniqueGlyph(ushort glyph, float width) { GlyphData glyphData = new GlyphData(glyph, width); if (UniqueGlyphs.BinarySearch(glyphData) >= 0) { return(null); } int i; for (i = 0; i < UniqueGlyphs.Count; i++) { if (glyphData.Glyph < UniqueGlyphs[i].Glyph) { UniqueGlyphs.Insert(i, glyphData); break; } } if (i == UniqueGlyphs.Count) { UniqueGlyphs.Add(glyphData); } return(glyphData); }
// todo: use this renderer; it's much better for monochrome fonts. for color there's still no better solution i know of. //// https://stackoverflow.com/questions/9080231/how-to-save-geometry-as-image //public static GenerateEmojiBitmapResults GenerateFontMap2(string fontName, int WidthAndHeight, string outputFileName) //{ // GlyphTypeface font; // if (File.Exists(fontName)) // { // font = new GlyphTypeface(new Uri(fontName)); // } // else // { // Typeface face = new Typeface(fontName); // face.TryGetGlyphTypeface(out font); // } // //int ColumnCount = 10; // //int MaxDrawCount = 30; // use int.MaxValue to draw them all // double fontSize = WidthAndHeight; // // the height of each cell has to include over/underhanging glyphs // SizeF cellSize = new SizeF((float)fontSize, (float)(fontSize * font.Height)); // var Glyphs = from glyphIndex in font.CharacterToGlyphMap.Values // select font.GetGlyphOutline(glyphIndex, fontSize, 1d); // int ColumnCount = (int)Math.Ceiling(Math.Sqrt(Glyphs.Count())); // // now create the visual we'll draw them to // DrawingVisual viz = new DrawingVisual(); // //int drawCount = -1; // using (DrawingContext dc = viz.RenderOpen()) // { // foreach (var g in Glyphs) // { // drawCount++; // if (g.IsEmpty()) continue; // don't draw the blank ones // // center horizontally in the cell // double xOffset = (drawCount % ColumnCount) * cellSize.Width + cellSize.Width / 2d - g.Bounds.Width / 2d; // // place the character on the baseline of the cell // double yOffset = (drawCount / ColumnCount) * cellSize.Height + fontSize * font.Baseline; // dc.PushTransform(new TranslateTransform(xOffset, yOffset)); // dc.DrawGeometry(System.Windows.Media.Brushes.Red, null, g); // dc.Pop(); // get rid of the transform // } // } // int RowCount = drawCount / ColumnCount; // if (drawCount % ColumnCount != 0) // RowCount++; // to include partial rows // int bitWidth = (int)Math.Ceiling((double)(cellSize.Width * ColumnCount)); // int bitHeight = (int)Math.Ceiling((double)(cellSize.Height * RowCount)); // RenderTargetBitmap bmp = new RenderTargetBitmap( // bitWidth, bitHeight, // 96, 96, // PixelFormats.Pbgra32); // bmp.Render(viz); // PngBitmapEncoder encoder = new PngBitmapEncoder(); // encoder.Frames.Add(BitmapFrame.Create(bmp)); // using (FileStream file = new FileStream(outputFileName, FileMode.Create)) // encoder.Save(file); //} public static GenerateEmojiBitmapResults GenerateEmojiBitmap(string fontName, int cellWidth, int cellHeight, float additionalScale, int shiftX, int shiftY, IEnumerable <EmojiInfo> codepointsToInclude, System.Drawing.Color[] backgroundPalette, System.Drawing.Color[] textPalette, float?aspectToleranceFromTarget, bool tryToFit, System.Windows.FontStyle fontStyle, System.Windows.FontWeight fontWeight, System.Windows.FontStretch fontStretch, bool strictGlyphChecking, d2.TextAntialiasMode aaMode) { System.Windows.Media.FontFamily fm = new System.Windows.Media.FontFamily(fontName); System.Windows.Media.Typeface tf = new System.Windows.Media.Typeface(fm, fontStyle, fontWeight, fontStretch); PetsciiMapgen.ProgressReporter pr = new PetsciiMapgen.ProgressReporter((ulong)codepointsToInclude.Count() * (ulong)backgroundPalette.Length * (ulong)textPalette.Length); if (!tf.TryGetGlyphTypeface(out System.Windows.Media.GlyphTypeface gtf)) { PetsciiMapgen.Log.WriteLine("!!!!!!!!!! FONT FAMILY HAS NO GLYPH MAP; you will end up with unsupported glyphs in the map."); // throw new Exception(); } // select codepoints to actually use PetsciiMapgen.Utils.ValueRangeInspector rangeX = new PetsciiMapgen.Utils.ValueRangeInspector(); PetsciiMapgen.Utils.ValueRangeInspector rangeY = new PetsciiMapgen.Utils.ValueRangeInspector(); PetsciiMapgen.Utils.ValueRangeInspector allAspects = new PetsciiMapgen.Utils.ValueRangeInspector(); PetsciiMapgen.Utils.ValueRangeInspector selectedAspects = new PetsciiMapgen.Utils.ValueRangeInspector(); int rejectedBecauseNotInTypeface = 0; int rejectedBecauseAspect = 0; int targetWidth = cellWidth; int targetHeight = cellHeight; float targetAspect = (float)targetWidth / targetHeight; EmojiTest.Direct2DText dt = new EmojiTest.Direct2DText(); dt.SetFont(fontName, targetHeight); var emoji = codepointsToInclude.Select(e => { pr.Visit(); GlyphData ret = new GlyphData(); ret.info = e; //ret.str = char.ConvertFromUtf32(cp); var sz = dt.GetTextSize(ret.info.str); ret.width = sz.Width; ret.height = sz.Height; rangeX.Visit(ret.width); rangeY.Visit(ret.height); allAspects.Visit(ret.width / ret.height); ret.scaleNeeded = 1; if (tryToFit) { if (ret.height > 0 && ret.width > 0) { float scaleNeededY = (float)targetHeight / ret.height;// factor to match target float scaleNeededX = (float)targetWidth / ret.width; ret.scaleNeeded = Math.Min(scaleNeededX, scaleNeededY); } else { ret.scaleNeeded = -1; } } return(ret); }) .Where(o => { if (o.info.forceInclude) { return(true); } if (o.info.str == "\r" || o.info.str == "\n") { return(false); } if (gtf != null) { if (!gtf.CharacterToGlyphMap.ContainsKey(o.info.cps[0])) { rejectedBecauseNotInTypeface++; if (strictGlyphChecking) { return(false); } } } float aspect = o.width / o.height; float da = Math.Abs(aspect - targetAspect); if (aspectToleranceFromTarget.HasValue && da > aspectToleranceFromTarget) { rejectedBecauseAspect++; return(false); } selectedAspects.Visit(aspect); return(true); }) .OrderBy(o => o.scaleNeeded).ToArray(); PetsciiMapgen.Log.WriteLine("EMOJI font encountered aspect ratios between {0}", allAspects); PetsciiMapgen.Log.WriteLine("Chars rejected because they don't have glyphs in this typeface: {0:N0}", rejectedBecauseNotInTypeface); PetsciiMapgen.Log.WriteLine("Chars rejected because aspect ratio out of range: {0:N0}", rejectedBecauseAspect); if (aspectToleranceFromTarget.HasValue) { PetsciiMapgen.Log.WriteLine("EMOJI font allowed aspect ratios between {0}", selectedAspects); } int totalCharCount = emoji.Count() * backgroundPalette.Length * textPalette.Length; int scaleChanges = 0; int columns = (int)Math.Ceiling(Math.Sqrt(totalCharCount)); int rows = columns;// we're aiming for square bitmap. int imgWidth = columns * targetWidth; int imgHeight = rows * targetHeight; List <GlyphData> fullEmoji = new List <GlyphData>(totalCharCount); if (emoji.Length < 2) { throw new Exception("NOt enough glyphs to generate anything meaningful."); } foreach (var backgroundColor in backgroundPalette) { foreach (var textColor in textPalette) { var bmp = new System.Drawing.Bitmap(imgWidth, imgHeight); using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp)) { float lastScale = 0; //int iemoji = 0; var pr2 = new PetsciiMapgen.ProgressReporter((ulong)emoji.Count()); //foreach (var e in emoji) for (int iemoji = 0; iemoji < emoji.Length; ++iemoji) { var e = emoji[iemoji]; pr2.Visit(); if (e.scaleNeeded <= 0) { continue; } if (Math.Abs(lastScale - e.scaleNeeded) > 0.001) { scaleChanges++; dt.SetFont(fontName, targetHeight * e.scaleNeeded * additionalScale); } //SharpDX.Size2F sz; var n = new GlyphData(e); fullEmoji.Add(n); RawColor4 bg = new RawColor4(backgroundColor.R / 255.0f, backgroundColor.G / 255.0f, backgroundColor.B / 255.0f, 1); dt.SetColor(textColor); n.bmp = dt.TextToBitmap(n.info.str, out n.bmpSize, bg, aaMode); // offset where to blit from, so it's centered. int ox = (int)((n.bmpSize.Width - targetWidth) / 2); int oy = (int)((n.bmpSize.Height - targetHeight) / 2); n.blitSourcRect = new System.Drawing.Rectangle(ox - shiftX, oy - shiftY, targetWidth, targetHeight); n.bgColor = backgroundColor; n.textColor = textColor; //int y = iemoji / columns; //int x = iemoji % columns; //g.DrawImage(bmpChar, // new System.Drawing.Rectangle(x * targetWidth, y * targetHeight, targetWidth, targetHeight), // new System.Drawing.Rectangle(ox - shiftX, oy - shiftY, targetWidth, targetHeight), System.Drawing.GraphicsUnit.Pixel // ); //bmpChar.Dispose(); //iemoji++; } } } } PetsciiMapgen.Log.WriteLine("Scale changes: {0}", scaleChanges); PetsciiMapgen.Log.WriteLine("Total char count: {0}", fullEmoji.Count); PetsciiMapgen.Log.WriteLine("Image size to hold entire colored charset: {0}, {1}", imgWidth, imgHeight); GenerateEmojiBitmapResults rv = new GenerateEmojiBitmapResults(); //rv.bmp = bmp; rv.columns = columns; rv.rows = rows; rv.AllCells = fullEmoji.ToArray(); return(rv); }
private IEnumerable<Point> CalculateAnnotationLocations(GlyphData[] pageLabels, AnnotationData annot) { if (annot.Annotation.PositionMethod == PositioningMethod.Absolute) { yield return annot.Annotation.Position; } IEnumerable<GlyphData> matches; switch (annot.Annotation.MatchMethod) { case null: case LabelMatchMethod.ExactMatch: matches = pageLabels.Where(g => g.Glyphs.UnicodeString == annot.LabelMatchText); break; case LabelMatchMethod.ExactMatchIgnoreCase: matches = pageLabels.Where(g => g.LowerCaseText == annot.LabelMatchText); break; case LabelMatchMethod.RegularExpression: matches = pageLabels.Where(g => annot.LabelMatcher.IsMatch(g.LowerCaseText)); break; default: throw new ArgumentOutOfRangeException("Invalid MatchMethod"); } foreach (var match in matches) { var glyphs = match.Glyphs; var anchorPos = glyphs.RenderTransform.Transform( new Point(glyphs.OriginX, glyphs.OriginY)); var pos = new Point(annot.Annotation.Position.X + anchorPos.X, (annot.Annotation.Position.Y + anchorPos.Y) - annot.Annotation.TextSize); yield return pos; } }
private void ApplyAnnotation(AnnotationData annot, FixedPage page, int pageNumber, GlyphData[] pageLabels, Canvas canvas) { foreach (var location in CalculateAnnotationLocations(pageLabels, annot)) { _annotatedPages.Add(pageNumber); var annotationText = new TextBlock(new Run(annot.Annotation.Text) { Foreground = GetForegroundBrush(annot.Annotation.ForegroundColor), FontSize = annot.Annotation.TextSize, FontWeight = annot.Annotation.FontWeight ?? FontWeights.Normal, FontFamily = new FontFamily(string.IsNullOrEmpty(annot.Annotation.FontName) ? "Arial" : annot.Annotation.FontName), FontStyle = annot.Annotation.IsItalic ? FontStyles.Italic : FontStyles.Normal }); if (annot.Annotation.CustomTransform != null) { annotationText.RenderTransform = annot.Annotation.CustomTransform; } Canvas.SetLeft(annotationText, location.X); Canvas.SetTop(annotationText, location.Y); canvas.Children.Add(annotationText); } }
public void DynamicRenderAtlas(GraphicsDevice gd, uint character, int texDims = 1024, uint baseChar = 0x54) { if (System.Threading.Thread.CurrentThread != GameMain.MainThread) { CrossThread.RequestExecutionOnMainThread(() => { DynamicRenderAtlas(gd, character, texDims, baseChar); }); return; } byte[] bitmap; int glyphWidth; int glyphHeight; Fixed26Dot6 horizontalAdvance; Vector2 drawOffset; lock (mutex) { if (texCoords.ContainsKey(character)) { return; } if (textures.Count == 0) { this.texDims = texDims; this.baseChar = baseChar; face.SetPixelSizes(0, size); face.LoadGlyph(face.GetCharIndex(baseChar), LoadFlags.Default, LoadTarget.Normal); baseHeight = face.Glyph.Metrics.Height.ToInt32(); textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color)); } uint glyphIndex = face.GetCharIndex(character); if (glyphIndex == 0) { return; } face.SetPixelSizes(0, size); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0) { if (face.Glyph.Metrics.HorizontalAdvance > 0) { //glyph is empty, but char still applies advance GlyphData blankData = new GlyphData(); blankData.advance = (float)face.Glyph.Metrics.HorizontalAdvance; blankData.texIndex = -1; //indicates no texture because the glyph is empty texCoords.Add(character, blankData); } return; } //stacktrace doesn't really work that well when RenderGlyph throws an exception face.Glyph.RenderGlyph(RenderMode.Normal); bitmap = (byte[])face.Glyph.Bitmap.BufferData.Clone(); glyphWidth = face.Glyph.Bitmap.Width; glyphHeight = bitmap.Length / glyphWidth; horizontalAdvance = face.Glyph.Metrics.HorizontalAdvance; drawOffset = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop); if (glyphWidth > texDims - 1 || glyphHeight > texDims - 1) { throw new Exception(filename + ", " + size.ToString() + ", " + (char)character + "; Glyph dimensions exceed texture atlas dimensions"); } currentDynamicAtlasNextY = Math.Max(currentDynamicAtlasNextY, glyphHeight + 2); if (currentDynamicAtlasCoords.X + glyphWidth + 2 > texDims - 1) { currentDynamicAtlasCoords.X = 0; currentDynamicAtlasCoords.Y += currentDynamicAtlasNextY; currentDynamicAtlasNextY = 0; } //no more room in current texture atlas, create a new one if (currentDynamicAtlasCoords.Y + glyphHeight + 2 > texDims - 1) { currentDynamicAtlasCoords.X = 0; currentDynamicAtlasCoords.Y = 0; currentDynamicAtlasNextY = 0; textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color)); currentDynamicPixelBuffer = null; } GlyphData newData = new GlyphData { advance = (float)horizontalAdvance, texIndex = textures.Count - 1, texCoords = new Rectangle((int)currentDynamicAtlasCoords.X, (int)currentDynamicAtlasCoords.Y, glyphWidth, glyphHeight), drawOffset = drawOffset }; texCoords.Add(character, newData); if (currentDynamicPixelBuffer == null) { currentDynamicPixelBuffer = new uint[texDims * texDims]; textures[newData.texIndex].GetData <uint>(currentDynamicPixelBuffer, 0, texDims * texDims); } for (int y = 0; y < glyphHeight; y++) { for (int x = 0; x < glyphWidth; x++) { byte byteColor = bitmap[x + y * glyphWidth]; currentDynamicPixelBuffer[((int)currentDynamicAtlasCoords.X + x) + ((int)currentDynamicAtlasCoords.Y + y) * texDims] = (uint)(byteColor << 24 | 0x00ffffff); } } textures[newData.texIndex].SetData <uint>(currentDynamicPixelBuffer); currentDynamicAtlasCoords.X += glyphWidth + 2; } }
/// <summary> /// Executes the glyph shader. /// </summary> /// <param name="data">The data for the glyph which is being drawn.</param> /// <param name="index">The index of the glyph within its source string.</param> public void Execute(ref GlyphData data, Int32 index) { glyphShader.Execute(ref this, ref data, index); }
public override void Execute(ref GlyphShaderContext context, ref GlyphData data, Int32 index) { data.Color = Colors[index % Colors.Length]; }
public string Serialize(GlyphData glyphData) { return(JsonSerializer.Serialize(glyphData)); }
internal void AddSymbol(char symbol, GlyphData glyphData) { if(Symbols.ContainsKey(symbol)) return; Symbols.Add(symbol, glyphData); }
SpriteFont #endif (Texture2D texture, Stream metricsDataStream, float internalScale) { this.texture = texture; this.internalScale = internalScale; using(BinaryReader br = new BinaryReader(metricsDataStream, Encoding.Unicode)) { // Check for signature "ExEnFont" if(br.ReadInt32() != 0x6E457845 || br.ReadInt32() != 0x746E6F46) throw new ContentLoadException("Invalid ExEn font metrics file"); if(br.ReadInt32() != 0) throw new ContentLoadException("Invalid version of ExEn font metrics file"); // Read common properties: LineSpacing = br.ReadInt32(); Spacing = br.ReadInt32(); if(br.ReadBoolean()) DefaultCharacter = br.ReadChar(); else DefaultCharacter = null; // Read glyph list: int count = br.ReadInt32(); for(int i = 0; i < count; i++) { char c = br.ReadChar(); GlyphData g = new GlyphData(); g.Glyph = br.ReadRectangle(); g.Cropping = br.ReadRectangle(); g.Kerning = br.ReadVector3(); characterData.Add(c, g); } } }
public string Serialize(GlyphData glyphData) { return(JsonConvert.SerializeObject(glyphData)); }
/// <summary> /// Applies a new set of rendered glyphs to the <see cref="Font"/>, adjusts its typeface metadata and clears out the <see cref="GlyphsDirty"/> flag. /// This method is used by the editor to update a Font after adjusting its properties. /// </summary> /// <param name="bitmap"></param> /// <param name="atlas"></param> /// <param name="glyphs"></param> /// <param name="metrics"></param> public void SetGlyphData(PixelData bitmap, Rect[] atlas, GlyphData[] glyphs, FontMetrics metrics) { this.ReleaseResources(); this.glyphs = glyphs; this.GenerateCharLookup(); this.pixelData = new Pixmap(bitmap); this.pixelData.Atlas = atlas.ToList(); this.metrics = metrics; // Copy metrics data into local fields. // Remove this on the next major version step. this.size = metrics.Size; this.height = metrics.Height; this.ascent = metrics.Ascent; this.bodyAscent = metrics.BodyAscent; this.descent = metrics.Descent; this.baseLine = metrics.BaseLine; this.monospace = metrics.Monospace; this.maxGlyphWidth = 0; for (int i = 0; i < this.glyphs.Length; i++) { this.maxGlyphWidth = Math.Max(this.maxGlyphWidth, this.glyphs[i].Width); } this.UpdateKerningData(); this.GenerateTexture(); this.GenerateMaterial(); }
public void GenerateFontSource(TextWriter writer, FontDescriptor fontDescriptor) { XmlWriterSettings settings = new XmlWriterSettings(); settings.CloseOutput = false; settings.Indent = true; settings.IndentChars = " "; XmlWriter wr = XmlWriter.Create(writer, settings); try { FontData fontData = new FontData(fontDescriptor.Font); wr.WriteStartDocument(); wr.WriteComment(" Creado con EosFontGenerator "); wr.WriteComment(" No modificar "); wr.WriteComment(String.Format(" Name : {0} ", fontData.Name)); wr.WriteComment(String.Format(" Size : {0}pt ", fontDescriptor.Font.SizeInPoints)); wr.WriteComment(String.Format(" Style : {0} ", fontDescriptor.Font.Style)); wr.WriteStartElement("resources"); wr.WriteStartElement("fontResource"); wr.WriteAttributeString("version", "2.0"); wr.WriteAttributeString("resourceId", fontData.Name.Replace(", ", "")); wr.WriteStartElement("font"); wr.WriteAttributeString("name", fontData.Name); wr.WriteAttributeString("height", fontData.Height.ToString()); wr.WriteAttributeString("ascent", fontData.Ascent.ToString()); wr.WriteAttributeString("descent", fontData.Descent.ToString()); foreach (CharacterDescriptor characterDescriptor in fontDescriptor.CharacterDescriptors) { char ch = characterDescriptor.Character; GlyphData glyphData = new GlyphData(characterDescriptor.Font, ch, GlyphFormat.L1); GlyphBitmap glyphBitmap = glyphData.Glyph; wr.WriteStartElement("char"); wr.WriteAttributeString("code", String.Format("0x{0:X2}", Convert.ToInt32(ch))); wr.WriteAttributeString("advance", glyphData.Advance.ToString()); if (glyphBitmap != null) { wr.WriteStartElement("bitmap"); wr.WriteAttributeString("format", "L1"); wr.WriteAttributeString("left", glyphBitmap.OffsetX.ToString()); wr.WriteAttributeString("top", glyphBitmap.OffsetY.ToString()); wr.WriteAttributeString("width", glyphBitmap.Width.ToString()); wr.WriteAttributeString("height", glyphBitmap.Height.ToString()); for (int y = 0; y < glyphBitmap.Height; y++) { wr.WriteStartElement("scanLine"); StringBuilder sb = new StringBuilder(); try { int black = Color.Black.ToArgb(); for (int x = 0; x < glyphBitmap.Width; x++) { if (glyphBitmap.Bitmap.GetPixel(x, y).ToArgb() == black) { sb.Append('1'); } else { sb.Append('.'); } } } catch { } wr.WriteString(sb.ToString()); wr.WriteEndElement(); } wr.WriteEndElement(); } wr.WriteEndElement(); } wr.WriteEndElement(); wr.WriteEndElement(); wr.WriteEndElement(); wr.WriteEndDocument(); } finally { wr.Close(); } }
public override void Execute(ref GlyphShaderContext context, ref GlyphData data, int index) { var offset = (Int32)(DateTime.UtcNow.TimeOfDay.TotalMilliseconds / 50); data.Color = colors[(index + offset) % colors.Length]; }
// load one single glyph into the cache private GlyphData Load(char glyph, FormatOptions formatOptions) { int fontId = GetFontId(IsAnsiChar(glyph) ? formatOptions.AnsiFont : formatOptions.Font); var font = m_registeredFonts[fontId]; uint glyphId = ((uint)fontId << 16) + glyph; GlyphData glyphData; if (m_loadedGlyphs.TryGetValue(glyphId, out glyphData)) { glyphData.m_timeStamp = m_timeStamp; return glyphData; } var str = glyph.ToString(); var chRect = MeasureCharacter(glyph, m_registeredFonts[fontId].m_fontObject); chRect.Inflate(font.m_outlineThickness * 0.5f, font.m_outlineThickness * 0.5f); int width = Math.Max((int)Math.Ceiling(chRect.Width), 1); int height = Math.Max((int)Math.Ceiling(chRect.Height), 1); int pagesInX = (width - 1) / PageSize + 1; int pagesInY = (height - 1) / PageSize + 1; GlyphPage[] pages = new GlyphPage[pagesInX * pagesInY]; for (int i = 0; i < pages.Length; ++i) { pages[i].m_x = i % pagesInX; pages[i].m_y = i / pagesInX; pages[i].m_pageIndex = RequestPage(); } using (var bmp = new SystemDrawing.Bitmap(pagesInX * PageSize, pagesInY * PageSize)) using (var g = SystemDrawing.Graphics.FromImage(bmp)) using (var memStream = new MemoryStream()) { // draw text using GDI+ g.TextRenderingHint = SystemDrawing.Text.TextRenderingHint.AntiAliasGridFit; g.SmoothingMode = SystemDrawing.Drawing2D.SmoothingMode.AntiAlias; g.InterpolationMode = SystemDrawing.Drawing2D.InterpolationMode.HighQualityBicubic; if (font.m_outlineThickness > 0) { SystemDrawing.Pen outlinePen; if (!m_outlinePensWithWidths.TryGetValue(font.m_outlineThickness, out outlinePen)) { outlinePen = new SystemDrawing.Pen(SystemDrawing.Color.Gray, font.m_outlineThickness); outlinePen.MiterLimit = font.m_outlineThickness; m_outlinePensWithWidths.Add(font.m_outlineThickness, outlinePen); } // draw outline using (var outlinePath = new SystemDrawing.Drawing2D.GraphicsPath()) { outlinePath.AddString(str, font.m_fontObject.FontFamily, (int)font.m_fontObject.Style, g.DpiX * font.m_fontObject.SizeInPoints / 72, new SystemDrawing.PointF(-chRect.Left, -chRect.Top), SystemDrawing.StringFormat.GenericDefault); g.DrawPath(outlinePen, outlinePath); g.FillPath(m_whiteBrush, outlinePath); } } else { g.DrawString(str, font.m_fontObject, m_whiteBrush, new SystemDrawing.PointF(-chRect.Left, -chRect.Top)); } bmp.Save(memStream, System.Drawing.Imaging.ImageFormat.Png); using (var tmpTexture = Texture2D.FromStream(GameApp.Instance.GraphicsDevice, memStream)) { var device = GameApp.Instance.GraphicsDevice; device.DepthStencilState = DepthStencilState.None; device.RasterizerState = RasterizerState.CullCounterClockwise; device.Indices = null; m_effect.CurrentTechnique = m_techBlit; m_paramTexture.SetValue(tmpTexture); foreach (var batch in pages.GroupBy(page => page.m_pageIndex / PagesInOneCacheTexture)) { var textureId = batch.Key; device.SetRenderTarget(m_cacheTextures[textureId].m_physicalRTTexture); device.BlendState = m_channelMasks[textureId % 4]; var pagesInBatch = batch.ToArray(); var vertices = new VertexDataBlit[pagesInBatch.Length * 6]; for (int i = 0; i < pagesInBatch.Length; ++i) { var page = pagesInBatch[i]; var dstRectLeft = (page.m_pageIndex % PagesInOneCacheTexture) % PagesInOneRow * PageSize; var dstRectTop = (page.m_pageIndex % PagesInOneCacheTexture) / PagesInOneRow * PageSize; float posLeft = (dstRectLeft - 0.5f) / CacheTextureSize * 2 - 1; float posTop = 1 - (dstRectTop - 0.5f) / CacheTextureSize * 2; float posWidth = PageSize / (float)CacheTextureSize * 2; float posHeight = -PageSize / (float)CacheTextureSize * 2; float uvLeft = page.m_x / (float)pagesInX; float uvTop = page.m_y / (float)pagesInY; float uvWidth = 1.0f / pagesInX; float uvHeight = 1.0f / pagesInY; // left-top vertices[i * 6 + 0].pos = new Vector2(posLeft, posTop); vertices[i * 6 + 0].uv = new Vector2(uvLeft, uvTop); // right-top vertices[i * 6 + 1].pos = vertices[i * 6 + 4].pos = new Vector2(posLeft + posWidth, posTop); vertices[i * 6 + 1].uv = vertices[i * 6 + 4].uv = new Vector2(uvLeft + uvWidth, uvTop); // left-bottom vertices[i * 6 + 2].pos = vertices[i * 6 + 3].pos = new Vector2(posLeft, posTop + posHeight); vertices[i * 6 + 2].uv = vertices[i * 6 + 3].uv = new Vector2(uvLeft, uvTop + uvHeight); // right-bottom vertices[i * 6 + 5].pos = new Vector2(posLeft + posWidth, posTop + posHeight); vertices[i * 6 + 5].uv = new Vector2(uvLeft + uvWidth, uvTop + uvHeight); } foreach (var pass in m_techBlit.Passes) { pass.Apply(); device.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, pagesInBatch.Length * 2); } } device.SetRenderTarget(null); } } glyphData = new GlyphData(); glyphData.m_pageIndices = new int[pagesInX, pagesInY]; pages.ForEach(page => glyphData.m_pageIndices[page.m_x, page.m_y] = page.m_pageIndex); glyphData.m_glyphSize = chRect.Size; glyphData.m_timeStamp = m_timeStamp; m_loadedGlyphs.Add(glyphId, glyphData); return glyphData; }
private void ProcessTextAdv(string text, int index, out GlyphData glyphData, out Rect uvRect, out float glyphXAdv, out float glyphXOff) { char glyph = text[index]; int charIndex = (int)glyph > CharLookup.Length ? 0 : CharLookup[(int)glyph]; this.texture.LookupAtlas(charIndex, out uvRect); this.GetGlyphData(glyph, out glyphData); glyphXOff = -glyphData.offsetX; if (this.kerning && !this.monospace && !this.needsReload) { char glyphNext = index + 1 < text.Length ? text[index + 1] : ' '; GlyphData glyphDataNext; this.GetGlyphData(glyphNext, out glyphDataNext); int minSum = int.MaxValue; for (int k = 0; k < glyphData.kerningSamplesRight.Length; k++) minSum = Math.Min(minSum, glyphData.kerningSamplesRight[k] + glyphDataNext.kerningSamplesLeft[k]); glyphXAdv = (this.monospace ? this.maxGlyphWidth : -glyphData.offsetX + glyphData.width) + this.spacing - minSum; } else glyphXAdv = (this.monospace ? this.maxGlyphWidth : -glyphData.offsetX + glyphData.width) + this.spacing; }
/// <summary> /// Retrieves information about a single glyph. /// </summary> /// <param name="glyph">The glyph to retrieve information about.</param> /// <param name="data">A struct holding the retrieved information.</param> /// <returns>True, if successful, false if the specified glyph is not supported.</returns> public bool GetGlyphData(char glyph, out GlyphData data) { int glyphId = (int)glyph; if (glyphId >= CharLookup.Length) { data = this.glyphs[0]; return false; } else { data = this.glyphs[CharLookup[glyphId]]; return true; } }
public override void Execute(ref GlyphShaderContext context, ref GlyphData data, int index) { data.X += r.Next(-2, 2); data.Y += r.Next(-2, 2); }
/// <summary> /// Renders the font into at least one texture atlas, which is simply a collection of all glyphs in the ranges defined by charRanges. /// Don't call this too often or with very large sizes. /// </summary> /// <param name="gd">Graphics device, required to create textures.</param> /// <param name="charRanges">Character ranges between each even element with their corresponding odd element. Default is 0x20 to 0xFFFF.</param> /// <param name="texDims">Texture dimensions. Default is 512x512.</param> /// <param name="baseChar">Base character used to shift all other characters downwards when rendering. Defaults to T.</param> public void RenderAtlas(GraphicsDevice gd, uint[] charRanges = null, int texDims = 512, uint baseChar = 0x54) { if (charRanges == null) { charRanges = new uint[] { 0x20, 0xFFFF }; } this.charRanges = charRanges; this.texDims = texDims; this.baseChar = baseChar; face.SetPixelSizes(0, size); textures.ForEach(t => t.Dispose()); textures.Clear(); texCoords.Clear(); uint[] pixelBuffer = new uint[texDims * texDims]; for (int i = 0; i < texDims * texDims; i++) { pixelBuffer[i] = 0; } textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color)); int texIndex = 0; Vector2 currentCoords = Vector2.Zero; int nextY = 0; face.LoadGlyph(face.GetCharIndex(baseChar), LoadFlags.Default, LoadTarget.Normal); baseHeight = face.Glyph.Metrics.Height.ToInt32(); //lineHeight = baseHeight; for (int i = 0; i < charRanges.Length; i += 2) { uint start = charRanges[i]; uint end = charRanges[i + 1]; for (uint j = start; j <= end; j++) { uint glyphIndex = face.GetCharIndex(j); if (glyphIndex == 0) { continue; } face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0) { if (face.Glyph.Metrics.HorizontalAdvance > 0) { //glyph is empty, but char still applies advance GlyphData blankData = new GlyphData(); blankData.advance = (float)face.Glyph.Metrics.HorizontalAdvance; blankData.texIndex = -1; //indicates no texture because the glyph is empty texCoords.Add(j, blankData); } continue; } //stacktrace doesn't really work that well when RenderGlyph throws an exception face.Glyph.RenderGlyph(RenderMode.Normal); byte[] bitmap = face.Glyph.Bitmap.BufferData; int glyphWidth = face.Glyph.Bitmap.Width; int glyphHeight = bitmap.Length / glyphWidth; //if (glyphHeight>lineHeight) lineHeight=glyphHeight; if (glyphWidth > texDims - 1 || glyphHeight > texDims - 1) { throw new Exception(filename + ", " + size.ToString() + ", " + (char)j + "; Glyph dimensions exceed texture atlas dimensions"); } nextY = Math.Max(nextY, glyphHeight + 2); if (currentCoords.X + glyphWidth + 2 > texDims - 1) { currentCoords.X = 0; currentCoords.Y += nextY; nextY = 0; } if (currentCoords.Y + glyphHeight + 2 > texDims - 1) { currentCoords.X = 0; currentCoords.Y = 0; textures[texIndex].SetData <uint>(pixelBuffer); textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color)); texIndex++; for (int k = 0; k < texDims * texDims; k++) { pixelBuffer[k] = 0; } } GlyphData newData = new GlyphData(); newData.advance = (float)face.Glyph.Metrics.HorizontalAdvance; newData.texIndex = texIndex; newData.texCoords = new Rectangle((int)currentCoords.X, (int)currentCoords.Y, glyphWidth, glyphHeight); newData.drawOffset = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop); texCoords.Add(j, newData); for (int y = 0; y < glyphHeight; y++) { for (int x = 0; x < glyphWidth; x++) { byte byteColor = bitmap[x + y * glyphWidth]; pixelBuffer[((int)currentCoords.X + x) + ((int)currentCoords.Y + y) * texDims] = (uint)(byteColor << 24 | byteColor << 16 | byteColor << 8 | byteColor); } } currentCoords.X += glyphWidth + 2; } textures[texIndex].SetData <uint>(pixelBuffer); } graphicsDevice = gd; }
/// <summary> /// Executes the glyph shader /// </summary> /// <param name="context">The current glyph shader context.</param> /// <param name="data">The data for the glyph being drawn.</param> /// <param name="index">The index of the glyph within its source string.</param> public abstract void Execute(ref GlyphShaderContext context, ref GlyphData data, Int32 index);
/// <summary> /// Applies a new set of rendered glyphs to the <see cref="Font"/>, adjusts its typeface metadata and clears out the <see cref="GlyphsDirty"/> flag. /// This method is used by the editor to update a Font after adjusting its properties. /// </summary> /// <param name="bitmap"></param> /// <param name="atlas"></param> /// <param name="glyphs"></param> /// <param name="height"></param> /// <param name="ascent"></param> /// <param name="bodyAscent"></param> /// <param name="descent"></param> /// <param name="baseLine"></param> public void SetGlyphData(PixelData bitmap, Rect[] atlas, GlyphData[] glyphs, int height, int ascent, int bodyAscent, int descent, int baseLine) { this.ReleaseResources(); this.glyphs = glyphs; this.GenerateCharLookup(); this.pixelData = new Pixmap(bitmap); this.pixelData.Atlas = atlas.ToList(); this.height = height; this.ascent = ascent; this.bodyAscent = bodyAscent; this.descent = descent; this.baseLine = baseLine; for (int i = 0; i < this.glyphs.Length; i++) { this.maxGlyphWidth = Math.Max(this.maxGlyphWidth, this.glyphs[i].Width); } this.UpdateKerningData(); this.GenerateTexMat(); this.glyphsDirty = false; }