private FontGlyph GetGlyph(Font font, int codepoint, int isize, int iblur, bool isBitmapRequired) { 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; float scale = 0; FontGlyph glyph = null; var size = isize / 10.0f; if (isize < 2) { return(null); } if (iblur > 20) { iblur = 20; } if (font.TryGetGlyph(codepoint, isize, iblur, out glyph)) { if (!isBitmapRequired || glyph.X0 >= 0 && glyph.Y0 >= 0) { return(glyph); } } g = font._font.fons__tt_getGlyphIndex(codepoint); if (g == 0) { throw new Exception(string.Format("Could not find glyph for codepoint {0}", codepoint)); } scale = font._font.fons__tt_getPixelHeightScale(size); font._font.fons__tt_buildGlyphBitmap(g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1); var pad = FontGlyph.PadFromBlur(iblur); gw = x1 - x0 + pad * 2; gh = y1 - y0 + pad * 2; var currentAtlas = CurrentAtlas; if (isBitmapRequired) { if (!currentAtlas.AddRect(gw, gh, ref gx, ref gy)) { var ev = CurrentAtlasFull; if (ev != null) { ev(this, EventArgs.Empty); } // This code will force creation of new atlas _currentAtlas = null; currentAtlas = CurrentAtlas; // Try to add again if (!currentAtlas.AddRect(gw, gh, ref gx, ref gy)) { throw new Exception(string.Format("Could not add rect to the newly created atlas. gw={0}, gh={1}", gw, gh)); } } } else { gx = -1; gy = -1; } if (glyph == null) { glyph = new FontGlyph { Codepoint = codepoint, Size = isize, Blur = iblur }; font.SetGlyph(codepoint, isize, iblur, glyph); } glyph.Index = g; glyph.AtlasIndex = currentAtlas.Index; glyph.X0 = gx; glyph.Y0 = gy; glyph.X1 = glyph.X0 + gw; glyph.Y1 = glyph.Y0 + gh; glyph.XAdvance = (int)(scale * advance * 10.0f); glyph.XOffset = x0 - pad; glyph.YOffset = y0 - pad; if (!isBitmapRequired) { return(glyph); } currentAtlas.RenderGlyph(font, glyph, gw, gh, scale); return(glyph); }
private FontGlyph GetGlyph(Font font, int codepoint, int isize, int iblur, bool isBitmapRequired, bool searchRecursively = true) { 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 renderFont = font; if (isize < 2) { return(null); } if (iblur > 20) { iblur = 20; } pad = iblur + 2; if (font.TryGetGlyph(codepoint, isize, iblur, out glyph)) { if (!isBitmapRequired || glyph.X0 >= 0 && glyph.Y0 >= 0) { return(glyph); } } g = font._font.fons__tt_getGlyphIndex(codepoint); // Look for the glyph in other loaded fonts if (g == 0) { if (searchRecursively) { foreach (var f in _fonts) { if (f == font) { continue; } var newGlyph = GetGlyph(f, codepoint, isize, iblur, true, false); g = f._font.fons__tt_getGlyphIndex(codepoint); if (g == 0) { continue; } return(newGlyph); } // No glyph was found at this point } } scale = renderFont._font.fons__tt_getPixelHeightScale(size); renderFont._font.fons__tt_buildGlyphBitmap(g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1); gw = x1 - x0 + pad * 2; gh = y1 - y0 + pad * 2; if (isBitmapRequired) { if (!_atlas.AddRect(gw, gh, ref gx, ref gy)) { var a = AtlasFull; if (a != null) { a(); } // Try again if (!_atlas.AddRect(gw, gh, ref gx, ref gy)) { throw new Exception("FONS_ATLAS_FULL"); } } } else { gx = -1; gy = -1; } if (glyph == null) { glyph = new FontGlyph { Codepoint = codepoint, Size = isize, Blur = iblur }; font.SetGlyph(codepoint, isize, iblur, glyph); } glyph.Index = g; glyph.X0 = gx; glyph.Y0 = gy; glyph.X1 = glyph.X0 + gw; glyph.Y1 = glyph.Y0 + gh; glyph.XAdvance = (int)(scale * advance * 10.0f); glyph.XOffset = x0 - pad; glyph.YOffset = y0 - pad; if (!isBitmapRequired) return(glyph); fixed(byte *dst = &_texData[glyph.X0 + pad + (glyph.Y0 + pad) * _params_.Width]) { renderFont._font.fons__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) { fixed(byte *bdst = &_texData[glyph.X0 + glyph.Y0 *_params_.Width]) { Blur(bdst, gw, gh, _params_.Width, iblur); } } _dirtyRect[0] = Math.Min(_dirtyRect[0], glyph.X0); _dirtyRect[1] = Math.Min(_dirtyRect[1], glyph.Y0); _dirtyRect[2] = Math.Max(_dirtyRect[2], glyph.X1); _dirtyRect[3] = Math.Max(_dirtyRect[3], glyph.Y1); return(glyph); }