// --- functions --- /// <summary>Gets data associated with the specified codepoint.</summary> /// <param name="text">The string containing the codepoint.</param> /// <param name="offset">The offset at which to read the codepoint. For surrogate pairs, two characters are read, and one otherwise.</param> /// <param name="texture">Receives the texture that contains the codepoint.</param> /// <param name="data">Receives the data that describes the codepoint.</param> /// <returns>The number of characters read.</returns> public int GetCharacterData(string text, int offset, out Texture texture, out OpenGlFontChar data) { int value = char.ConvertToUtf32(text, offset); int hi = value >> 8; int lo = value & 0xFF; if (Tables[hi] == null || Tables[hi].Texture == null) { lock (BaseRenderer.GdiPlusLock) { Tables[hi] = new OpenGlFontTable(Font, hi << 8); } } texture = Tables[hi].Texture; data = Tables[hi].Characters[lo]; return(value >= 0x10000 ? 2 : 1); }
// --- constructors --- /// <summary>Creates a new table of characters.</summary> /// <param name="font">The font.</param> /// <param name="offset">The offset from codepoint U+0000.</param> public OpenGlFontTable(Font font, int offset) { /* * Measure characters. * */ Size[] physicalSizes = new Size[256]; Size[] typographicSizes = new Size[256]; bitmap = new Bitmap(1, 1, PixelFormat.Format32bppArgb); Graphics graphics = Graphics.FromImage(bitmap); graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; for (int i = 0; i < 256; i++) { string character = char.ConvertFromUtf32(offset + i); SizeF physicalSize = graphics.MeasureString(character, font, int.MaxValue, StringFormat.GenericDefault); SizeF typographicSize = graphics.MeasureString(character, font, int.MaxValue, StringFormat.GenericTypographic); physicalSizes[i] = new Size((int)Math.Ceiling(physicalSize.Width), (int)Math.Ceiling(physicalSize.Height)); typographicSizes[i] = new Size((int)Math.Ceiling(typographicSize.Width == 0.0f ? physicalSize.Width : typographicSize.Width), (int)Math.Ceiling(typographicSize.Height == 0.0f ? physicalSize.Height : typographicSize.Height)); } graphics.Dispose(); bitmap.Dispose(); /* * Find suitable bitmap dimensions. * */ const int border = 1; int width = border; int height = border; int lineWidth = 0; int lineHeight = 0; PointF[] coordinates = new PointF[256]; for (int i = 0; i < 256; i++) { if (i % 16 == 0) { // new line if (lineWidth > width) { width = lineWidth; } lineWidth = border; height += lineHeight; lineHeight = 0; } coordinates[i] = new PointF(lineWidth, height); lineWidth += physicalSizes[i].Width + border; if (physicalSizes[i].Height + border > lineHeight) { lineHeight = physicalSizes[i].Height + border; } } if (lineWidth > width) { width = lineWidth; } height += lineHeight; width = (int)RoundToPowerOfTwo((uint)width); height = (int)RoundToPowerOfTwo((uint)height); /* * Draw character to bitmap. * */ bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); graphics = Graphics.FromImage(bitmap); graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; graphics.Clear(Color.Black); Characters = new OpenGlFontChar[256]; for (int i = 0; i < 256; i++) { graphics.DrawString(char.ConvertFromUtf32(offset + i), font, Brushes.White, coordinates[i]); float x0 = (coordinates[i].X - border) / width; float x1 = (coordinates[i].X + physicalSizes[i].Width + border) / width; float y0 = (coordinates[i].Y - border) / height; float y1 = (coordinates[i].Y + physicalSizes[i].Height + border) / height; Characters[i] = new OpenGlFontChar(new RectangleF(x0, y0, x1 - x0, y1 - y0), new Size(physicalSizes[i].Width + 2 * border, physicalSizes[i].Height + 2 * border), typographicSizes[i]); } graphics.Dispose(); Texture = new Texture(bitmap); }