public void GetQuad(Font font, int prevGlyphIndex, FontGlyph *glyph, float scale, float spacing, ref float x, ref float y, FontGlyphSquad *q) { float rx = 0; float ry = 0; float xoff = 0; float yoff = 0; float x0 = 0; float y0 = 0; float x1 = 0; float y1 = 0; if (prevGlyphIndex != -1) { var adv = font.FontInfo.__tt_getGlyphKernAdvance(prevGlyphIndex, glyph->Index) * scale; x += (int)(adv + spacing + 0.5f); } xoff = (short)(glyph->XOffset + 1); yoff = (short)(glyph->YOffset + 1); x0 = glyph->X0 + 1; y0 = glyph->Y0 + 1; x1 = glyph->X1 - 1; y1 = glyph->Y1 - 1; if ((_params_.Flags & FONS_ZERO_TOPLEFT) != 0) { rx = (int)(x + xoff); ry = (int)(y + yoff); q->X0 = rx; q->Y0 = ry; q->X1 = rx + x1 - x0; q->Y1 = ry + y1 - y0; q->S0 = x0 * _itw; q->T0 = y0 * _ith; q->S1 = x1 * _itw; q->T1 = y1 * _ith; } else { rx = (int)(x + xoff); ry = (int)(y - yoff); q->X0 = rx; q->Y0 = ry; q->X1 = rx + x1 - x0; q->Y1 = ry - y1 + y0; q->S0 = x0 * _itw; q->T0 = y0 * _ith; q->S1 = x1 * _itw; q->T1 = y1 * _ith; } x += (int)(glyph->XAdvance / 10.0f + 0.5f); }
public float TextBounds(float x, float y, StringSegment str, ref Bounds bounds) { var state = GetState(); var q = new FontGlyphSquad(); FontGlyph *glyph = null; var prevGlyphIndex = -1; var isize = (short)(state.Size * 10.0f); var iblur = (short)state.Blur; float scale = 0; Font font; float startx = 0; float advance = 0; float minx = 0; float miny = 0; float maxx = 0; float maxy = 0; if (state.Font < 0 || state.Font >= _fontsNumber) { return(0); } font = _fonts[state.Font]; if (font.Data == null) { return(0); } scale = font.FontInfo.__tt_getPixelHeightScale(isize / 10.0f); y += GetVertAlign(font, state.Align, isize); minx = maxx = x; miny = maxy = y; startx = x; for (int i = 0; i < str.Length; i += Char.IsSurrogatePair(str.String, i + str.Location) ? 2 : 1) { var codepoint = Char.ConvertToUtf32(str.String, i + str.Location); glyph = GetGlyph(font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_OPTIONAL); if (glyph != null) { GetQuad(font, prevGlyphIndex, glyph, scale, state.Spacing, ref x, ref y, &q); if (q.X0 < minx) { minx = q.X0; } if (q.X1 > maxx) { maxx = q.X1; } if ((_params_.Flags & FONS_ZERO_TOPLEFT) != 0) { if (q.Y0 < miny) { miny = q.Y0; } if (q.Y1 > maxy) { maxy = q.Y1; } } else { if (q.Y1 < miny) { miny = q.Y1; } if (q.Y0 > maxy) { maxy = q.Y0; } } } prevGlyphIndex = glyph != null ? glyph->Index : -1; } advance = x - startx; if ((state.Align & Alignment.Left) != 0) { } else if ((state.Align & Alignment.Right) != 0) { minx -= advance; maxx -= advance; } else if ((state.Align & Alignment.Center) != 0) { minx -= advance * 0.5f; maxx -= advance * 0.5f; } bounds.b1 = minx; bounds.b2 = miny; bounds.b3 = maxx; bounds.b4 = maxy; return(advance); }
public FontGlyph *GetGlyph(Font font, int codepoint, short isize, short iblur, int bitmapOption) { var i = 0; var g = 0; var advance = 0; var lsb = 0; var x0 = 0; var y0 = 0; var x1 = 0; var y1 = 0; var gw = 0; var gh = 0; var gx = 0; var gy = 0; var x = 0; var y = 0; float scale = 0; FontGlyph *glyph = null; int h = 0; var size = isize / 10.0f; var pad = 0; var added = 0; var renderFont = font; if (isize < 2) { return(null); } if (iblur > 20) { iblur = 20; } pad = iblur + 2; _scratchCount = 0; h = HashInt(codepoint) & (256 - 1); i = font.Lut[h]; while (i != -1) { if (font.Glyphs[i].Codepoint == codepoint && font.Glyphs[i].Size == isize && font.Glyphs[i].Blur == iblur) { glyph = &font.Glyphs[i]; if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL || glyph->X0 >= 0 && glyph->Y0 >= 0) { return(glyph); } break; } i = font.Glyphs[i].Next; } g = font.FontInfo.__tt_getGlyphIndex((int)codepoint); if (g == 0) { for (i = 0; i < font.FallbacksCount; ++i) { var fallbackFont = _fonts[font.Fallbacks[i]]; var fallbackIndex = fallbackFont.FontInfo.__tt_getGlyphIndex((int)codepoint); if (fallbackIndex != 0) { g = fallbackIndex; renderFont = fallbackFont; break; } } } scale = renderFont.FontInfo.__tt_getPixelHeightScale(size); renderFont.FontInfo.__tt_buildGlyphBitmap(g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1); gw = x1 - x0 + pad * 2; gh = y1 - y0 + pad * 2; if (bitmapOption == FONS_GLYPH_BITMAP_REQUIRED) { added = atlas.AddRect(gw, gh, &gx, &gy); if (added == 0) { throw new Exception("FONS_ATLAS_FULL"); } } else { gx = -1; gy = -1; } if (glyph == null) { glyph = AllocGlyph(font); glyph->Codepoint = codepoint; glyph->Size = isize; glyph->Blur = iblur; glyph->Next = 0; glyph->Next = font.Lut[h]; font.Lut[h] = font.GlyphsNumber - 1; } glyph->Index = g; glyph->X0 = (short)gx; glyph->Y0 = (short)gy; glyph->X1 = (short)(glyph->X0 + gw); glyph->Y1 = (short)(glyph->Y0 + gh); glyph->XAdvance = (short)(scale * advance * 10.0f); glyph->XOffset = (short)(x0 - pad); glyph->YOffset = (short)(y0 - pad); if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL) { return(glyph); fixed(byte *dst = &_texData[glyph->X0 + pad + (glyph->Y0 + pad) * _params_.Width]) { renderFont.FontInfo.__tt_renderGlyphBitmap(dst, gw - pad * 2, gh - pad * 2, _params_.Width, scale, scale, g); } fixed(byte *dst = &_texData[glyph->X0 + glyph->Y0 *_params_.Width]) { for (y = 0; y < gh; y++) { dst[y * _params_.Width] = 0; dst[gw - 1 + y * _params_.Width] = 0; } for (x = 0; x < gw; x++) { dst[x] = 0; dst[x + (gh - 1) * _params_.Width] = 0; } } if (iblur > 0) { _scratchCount = 0; fixed(byte *bdst = &_texData[glyph->X0 + glyph->Y0 *_params_.Width]) { Blur(bdst, gw, gh, _params_.Width, iblur); } } _dirtyRect[0] = Mini(_dirtyRect[0], glyph->X0); _dirtyRect[1] = Mini(_dirtyRect[1], glyph->Y0); _dirtyRect[2] = Maxi(_dirtyRect[2], glyph->X1); _dirtyRect[3] = Maxi(_dirtyRect[3], glyph->Y1); return(glyph); }