void GetQuad(FontGlyph glyph, FontGlyph prevGlyph, GlyphCollection collection, float spacing, ref float x, ref float y, FontGlyphSquad *q) { if (prevGlyph != null) { float adv = 0; if (UseKernings && glyph.Font == prevGlyph.Font) { adv = prevGlyph.Font.GetGlyphKernAdvance(prevGlyph.Index, glyph.Index) * glyph.Font.Scale; } x += (int)(adv + spacing + 0.5f); } float rx = 0; float ry = 0; rx = x + glyph.XOffset; ry = y + glyph.YOffset; q->X0 = rx; q->Y0 = ry; q->X1 = rx + glyph.Bounds.Width; q->Y1 = ry + glyph.Bounds.Height; q->S0 = glyph.Bounds.X * _itw; q->T0 = glyph.Bounds.Y * _ith; q->S1 = glyph.Bounds.Right * _itw; q->T1 = glyph.Bounds.Bottom * _ith; x += (int)(glyph.XAdvance / 10.0f + 0.5f); }
FontGlyph GetGlyphWithoutBitmap(GlyphCollection collection, int codepoint) { FontGlyph glyph = null; if (collection.Glyphs.TryGetValue(codepoint, out glyph)) { return(glyph); } Font font; var g = GetCodepointIndex(codepoint, out font); if (g == 0) { collection.Glyphs[codepoint] = null; return(null); } int advance, lsb, x0, y0, x1, y1; font.BuildGlyphBitmap(g, FontSize, font.Scale, &advance, &lsb, &x0, &y0, &x1, &y1); var pad = Math.Max(FontGlyph.PadFromBlur(BlurAmount), FontGlyph.PadFromBlur(StrokeAmount)); var gw = x1 - x0 + pad * 2; var gh = y1 - y0 + pad * 2; var offset = FontGlyph.PadFromBlur(BlurAmount); glyph = new FontGlyph { Font = font, Codepoint = codepoint, Size = FontSize, Index = g, Bounds = new Rectangle(0, 0, gw, gh), XAdvance = (int)(font.Scale * advance * 10.0f), XOffset = x0 - offset, YOffset = y0 - offset }; collection.Glyphs[codepoint] = glyph; return(glyph); }
public void RenderGlyph(GraphicsDevice device, FontGlyph glyph, int blurAmount, int strokeAmount) { var pad = Math.Max(FontGlyph.PadFromBlur(blurAmount), FontGlyph.PadFromBlur(strokeAmount)); // Render glyph to byte buffer var bufferSize = glyph.Bounds.Width * glyph.Bounds.Height; var buffer = _byteBuffer; if ((buffer == null) || (buffer.Length < bufferSize)) { buffer = new byte[bufferSize]; _byteBuffer = buffer; } Array.Clear(buffer, 0, bufferSize); var g = glyph.Index; var colorSize = glyph.Bounds.Width * glyph.Bounds.Height; var colorBuffer = _colorBuffer; if ((colorBuffer == null) || (colorBuffer.Length < colorSize)) { colorBuffer = new Color[colorSize]; _colorBuffer = colorBuffer; } fixed(byte *dst = &buffer[pad + pad *glyph.Bounds.Width]) { glyph.Font.RenderGlyphBitmap(dst, glyph.Bounds.Width - pad * 2, glyph.Bounds.Height - pad * 2, glyph.Bounds.Width, g); } if (strokeAmount > 0) { var width = glyph.Bounds.Width; var top = width * strokeAmount; var bottom = (glyph.Bounds.Height - strokeAmount) * glyph.Bounds.Width; var right = glyph.Bounds.Width - strokeAmount; var left = strokeAmount; byte d; for (var i = 0; i < colorSize; ++i) { var col = buffer[i]; var black = 0; if (col == 255) { colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = colorBuffer[i].A = 255; continue; } if (i >= top) { black = buffer[i - top]; } if (i < bottom) { d = buffer[i + top]; black = ((255 - d) * black + 255 * d) / 255; } if (i % width >= left) { d = buffer[i - strokeAmount]; black = ((255 - d) * black + 255 * d) / 255; } if (i % width < right) { d = buffer[i + strokeAmount]; black = ((255 - d) * black + 255 * d) / 255; } if (black == 0) { if (col == 0) { colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = colorBuffer[i].A = 0; //black transparency to suit stroke continue; } #if PREMULTIPLIEDALPHA colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = colorBuffer[i].A = col; #else colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = 255; colorBuffer[i].A = col; #endif } else { if (col == 0) { colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = 0; colorBuffer[i].A = (byte)black; continue; } #if PREMULTIPLIEDALPHA var alpha = ((255 - col) * black + 255 * col) / 255; colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = (byte)((alpha * col) / 255); colorBuffer[i].A = (byte)alpha; #else colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = col; colorBuffer[i].A = (byte)(((255 - col) * black + 255 * col) / 255); #endif } } } else { if (blurAmount > 0) { fixed(byte *bdst = &buffer[0]) { Blur(bdst, glyph.Bounds.Width, glyph.Bounds.Height, glyph.Bounds.Width, blurAmount); } } for (var i = 0; i < colorSize; ++i) { var c = buffer[i]; #if PREMULTIPLIEDALPHA colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = colorBuffer[i].A = c; #else colorBuffer[i].R = colorBuffer[i].G = colorBuffer[i].B = 255; colorBuffer[i].A = c; #endif } } // Write to texture if (Texture == null) { Texture = new Texture2D(device, Width, Height); } #if TEXTURESETDATAEXT fixed(Color *p = colorBuffer) #if FNA Texture.SetDataPointerEXT(0, glyph.Bounds, (IntPtr)p, colorSize * sizeof(Color)); #else Texture.SetDataEXT(0, 0, glyph.Bounds, (IntPtr)p, colorSize * sizeof(Color)); #endif #else Texture.SetData(0, 0, glyph.Bounds, colorBuffer, 0, colorSize); #endif }
public float TextBounds(float x, float y, StringBuilder str, ref Bounds bounds) { if (str == null || str.Length <= 0) { return(0.0f); } var collection = GetGlyphsCollection(FontSize); // Determine ascent and lineHeight from first character float ascent = 0, lineHeight = 0; for (var i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) { var codepoint = StringBuilderConvertToUtf32(str, i); var glyph = GetGlyph(null, collection, codepoint); if (glyph == null) { continue; } ascent = glyph.Font.Ascent; lineHeight = glyph.Font.LineHeight; break; } var q = new FontGlyphSquad(); float startx = 0; float advance = 0; y += ascent; float minx, maxx, miny, maxy; minx = maxx = x; miny = maxy = y; startx = x; FontGlyph prevGlyph = null; for (var i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) { var codepoint = StringBuilderConvertToUtf32(str, i); if (codepoint == '\n') { x = startx; y += lineHeight; prevGlyph = null; continue; } var glyph = GetGlyph(null, collection, codepoint); if (glyph == null) { continue; } GetQuad(glyph, prevGlyph, collection, Spacing, ref x, ref y, &q); if (q.X0 < minx) { minx = q.X0; } if (x > maxx) { maxx = x; } if (q.Y0 < miny) { miny = q.Y0; } if (q.Y1 > maxy) { maxy = q.Y1; } prevGlyph = glyph; } advance = x - startx; bounds.X = minx; bounds.Y = miny; bounds.X2 = maxx; bounds.Y2 = maxy; return(advance); }
public float DrawText(SpriteBatch batch, float x, float y, string str, float depth, Color color, Vector2 origin, float scaleX, float scaleY, SpriteEffects spriteEffects) { if (string.IsNullOrEmpty(str)) { return(0.0f); } var collection = GetGlyphsCollection(FontSize); // Determine ascent and lineHeight from first character float ascent = 0, lineHeight = 0; for (var i = 0; i < str.Length; i += char.IsSurrogatePair(str, i) ? 2 : 1) { var codepoint = char.ConvertToUtf32(str, i); var glyph = GetGlyph(batch.GraphicsDevice, collection, codepoint); if (glyph == null) { continue; } ascent = glyph.Font.Ascent; lineHeight = glyph.Font.LineHeight; break; } var q = new FontGlyphSquad(); var originX = -origin.X; var originY = -origin.Y; originY += ascent; FontGlyph prevGlyph = null; for (var i = 0; i < str.Length; i += char.IsSurrogatePair(str, i) ? 2 : 1) { var codepoint = char.ConvertToUtf32(str, i); if (codepoint == '\n') { originX = 0.0f; originY += lineHeight; prevGlyph = null; continue; } var glyph = GetGlyph(batch.GraphicsDevice, collection, codepoint); if (glyph == null) { continue; } GetQuad(glyph, prevGlyph, collection, Spacing, ref originX, ref originY, &q); var sourceRect = new Rectangle((int)(q.S0 * _size.X), (int)(q.T0 * _size.Y), (int)((q.S1 - q.S0) * _size.X), (int)((q.T1 - q.T0) * _size.Y)); batch.Draw(glyph.Atlas.Texture, new Vector2(x + q.X0 * scaleX, y + q.Y0 * scaleY), sourceRect, color, 0f, Vector2.Zero, new Vector2(scaleX, scaleY), spriteEffects, depth); prevGlyph = glyph; } return(x); }
public float DrawText(SpriteBatch batch, float x, float y, StringBuilder str, float depth) { if (str.Length == 0) { return(0.0f); } var collection = GetGlyphsCollection(FontSize); // Determine ascent and lineHeight from first character float ascent = 0, lineHeight = 0; for (var i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) { var codepoint = StringBuilderConvertToUtf32(str, i); var glyph = GetGlyph(batch.GraphicsDevice, collection, codepoint); if (glyph == null) { continue; } ascent = glyph.Font.Ascent; lineHeight = glyph.Font.LineHeight; break; } var q = new FontGlyphSquad(); var originX = 0.0f; var originY = 0.0f; originY += ascent; FontGlyph prevGlyph = null; for (var i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) { var codepoint = StringBuilderConvertToUtf32(str, i); if (codepoint == '\n') { originX = 0.0f; originY += lineHeight; prevGlyph = null; continue; } var glyph = GetGlyph(batch.GraphicsDevice, collection, codepoint); if (glyph == null) { continue; } GetQuad(glyph, prevGlyph, collection, Spacing, ref originX, ref originY, &q); q.X0 = (int)(q.X0 * Scale.X); q.X1 = (int)(q.X1 * Scale.X); q.Y0 = (int)(q.Y0 * Scale.Y); q.Y1 = (int)(q.Y1 * Scale.Y); var destRect = new Rectangle((int)(x + q.X0), (int)(y + q.Y0), (int)(q.X1 - q.X0), (int)(q.Y1 - q.Y0)); var sourceRect = new Rectangle((int)(q.S0 * _size.X), (int)(q.T0 * _size.Y), (int)((q.S1 - q.S0) * _size.X), (int)((q.T1 - q.T0) * _size.Y)); batch.Draw(glyph.Atlas.Texture, destRect, sourceRect, Color, 0f, Vector2.Zero, SpriteEffects.None, depth); prevGlyph = glyph; } return(x); }