diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index 6e507d42..501a13c7 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -59,10 +59,6 @@ namespace OpenTK.Graphics.Text { TextExtents extents = rasterizer.MeasureText(block); - foreach (char c in block.Text) - if (c != '\n' && c != '\r' && !Char.IsWhiteSpace(c) && !cache.Contains(c, block.Font)) - cache.Add(c, block.Font); - //GL.BindTexture(TextureTarget.Texture2D, 2); //GL.Begin(BeginMode.Quads); @@ -82,20 +78,20 @@ namespace OpenTK.Graphics.Text // Build layout int current = 0; - foreach (char c in block.Text) + foreach (Glyph glyph in block) { - if (c == '\n' || c == '\r') - continue; - else if (Char.IsWhiteSpace(c)) + if (glyph.IsWhiteSpace) { current++; continue; } + else if (!cache.Contains(glyph)) + cache.Add(glyph); - CachedGlyphInfo info = cache[c, block.Font]; + CachedGlyphInfo info = cache[glyph]; RectangleF position = extents[current++]; - // Use the real glyph width instead of the measured one - // (we want to achieve pixel perfect output). + + // Use the real glyph width instead of the measured one (we want to achieve pixel perfect output). position.Size = info.Rectangle.Size; if (!active_lists.ContainsKey(info.Texture)) diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index 9ca42400..8709bfc7 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -49,6 +49,9 @@ namespace OpenTK.Graphics.Text TextExtents extents = new TextExtents(); + Bitmap glyph_surface; + System.Drawing.Graphics glyph_renderer; + // Check the constructor, too, for additional flags. static readonly StringFormat default_string_format = StringFormat.GenericTypographic; static readonly StringFormat load_glyph_string_format = StringFormat.GenericDefault; @@ -75,15 +78,14 @@ namespace OpenTK.Graphics.Text public Bitmap Rasterize(Glyph glyph) { - using (Bitmap bmp = new Bitmap((int)(2 * glyph.Font.Size), (int)(2 * glyph.Font.Size))) - using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp)) - { - SetTextRenderingOptions(gfx, glyph.Font); + EnsureSurfaceSize(ref glyph_surface, ref glyph_renderer, glyph.Font); - gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, - glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format); - return bmp.Clone(FindEdges(bmp), System.Drawing.Imaging.PixelFormat.Format32bppArgb); - } + SetTextRenderingOptions(glyph_renderer, glyph.Font); + + glyph_renderer.Clear(Color.Transparent); + glyph_renderer.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, + glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format); + return glyph_surface.Clone(FindEdges(glyph_surface), System.Drawing.Imaging.PixelFormat.Format32bppArgb); } #endregion @@ -111,6 +113,24 @@ namespace OpenTK.Graphics.Text #region Private Members + #region EnsureSurfaceSize + + void EnsureSurfaceSize(ref Bitmap bmp, ref System.Drawing.Graphics gfx, Font font) + { + if (bmp == null || bmp.Width < 2 * font.Size || bmp.Height < 2 * font.Size) + { + if (bmp != null) + bmp.Dispose(); + if (gfx != null) + gfx.Dispose(); + + bmp = new Bitmap((int)(2 * font.Size), (int)(2 * font.Size)); + gfx = System.Drawing.Graphics.FromImage(bmp); + } + } + + #endregion + #region SetRenderingOptions // Modify rendering settings (antialiasing, grid fitting) to improve appearance. diff --git a/Source/Utilities/Graphics/Text/Glyph.cs b/Source/Utilities/Graphics/Text/Glyph.cs index f60ce3e6..b48bb084 100644 --- a/Source/Utilities/Graphics/Text/Glyph.cs +++ b/Source/Utilities/Graphics/Text/Glyph.cs @@ -54,8 +54,8 @@ namespace OpenTK.Graphics.Text #endregion - #region --- Public Methods --- - + #region Public Methods + #region public char Character /// @@ -88,6 +88,15 @@ namespace OpenTK.Graphics.Text #endregion + #region public bool IsWhiteSpace + + public bool IsWhiteSpace + { + get { return Char.IsWhiteSpace(Character); } + } + + #endregion + #region public override bool Equals(object obj) /// diff --git a/Source/Utilities/Graphics/Text/GlyphCache.cs b/Source/Utilities/Graphics/Text/GlyphCache.cs index 514f43ee..d09b508f 100644 --- a/Source/Utilities/Graphics/Text/GlyphCache.cs +++ b/Source/Utilities/Graphics/Text/GlyphCache.cs @@ -27,15 +27,11 @@ using System; using System.Collections.Generic; -using System.Text; using System.Drawing; -using OpenTK.Graphics; -using System.Diagnostics; - namespace OpenTK.Graphics.Text { - class GlyphCache + class GlyphCache// : IGlyphCache { #region Fields @@ -62,9 +58,8 @@ namespace OpenTK.Graphics.Text #region Public Members - public void Add(char c, Font font) + public void Add(Glyph glyph) { - Glyph glyph = new Glyph(c, font); bool inserted = false; using (Bitmap bmp = rasterizer.Rasterize(glyph)) @@ -91,27 +86,9 @@ namespace OpenTK.Graphics.Text } } - void InsertGlyph(Glyph glyph, Bitmap bmp, GlyphSheet sheet) + public bool Contains(Glyph glyph) { - Rectangle source = new Rectangle(0, 0, bmp.Width, bmp.Height); - Rectangle target = sheet.Packer.Add(source); - - sheet.Texture.WriteRegion(source, target, 0, bmp); - - cached_glyphs.Add(glyph, new CachedGlyphInfo(sheet.Texture, target)); - } - - public bool Contains(char c, Font font) - { - return cached_glyphs.ContainsKey(new Glyph(c, font)); - } - - public CachedGlyphInfo this[char c, Font font] - { - get - { - return cached_glyphs[new Glyph(c, font)]; - } + return cached_glyphs.ContainsKey(glyph); } public CachedGlyphInfo this[Glyph glyph] @@ -123,5 +100,19 @@ namespace OpenTK.Graphics.Text } #endregion + + #region Private Members + + void InsertGlyph(Glyph glyph, Bitmap bmp, GlyphSheet sheet) + { + Rectangle source = new Rectangle(0, 0, bmp.Width, bmp.Height); + Rectangle target = sheet.Packer.Add(source); + + sheet.Texture.WriteRegion(source, target, 0, bmp); + + cached_glyphs.Add(glyph, new CachedGlyphInfo(sheet.Texture, target)); + } + + #endregion } } diff --git a/Source/Utilities/Graphics/Text/GlyphEnumerator.cs b/Source/Utilities/Graphics/Text/GlyphEnumerator.cs new file mode 100644 index 00000000..08d7d64b --- /dev/null +++ b/Source/Utilities/Graphics/Text/GlyphEnumerator.cs @@ -0,0 +1,107 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics.Text +{ + class GlyphEnumerator : IEnumerator + { + #region Fields + + string text; + Font font; + + IEnumerator implementation; + + #endregion + + #region Constructors + + public GlyphEnumerator(string text, Font font) + { + if (text == null) + throw new ArgumentNullException("text"); + + if (font == null) + throw new ArgumentNullException("font"); + + this.text = text; + this.font = font; + + implementation = text.GetEnumerator(); + } + + #endregion + + #region IEnumerator Members + + public Glyph Current + { + get { return new Glyph(implementation.Current, font); } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + implementation.Dispose(); + } + + #endregion + + #region IEnumerator Members + + object System.Collections.IEnumerator.Current + { + get { return new Glyph(implementation.Current, font); } + } + + public bool MoveNext() + { + bool status; + do + { + status = implementation.MoveNext(); + } while (status && (implementation.Current == '\n' || implementation.Current == '\r')); + + return status; + } + + public void Reset() + { + implementation.Reset(); + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/IGlyphCache.cs b/Source/Utilities/Graphics/Text/IGlyphCache.cs new file mode 100644 index 00000000..d65c23c4 --- /dev/null +++ b/Source/Utilities/Graphics/Text/IGlyphCache.cs @@ -0,0 +1,36 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + +namespace OpenTK.Graphics.Text +{ + interface IGlyphCache + { + void Add(Glyph glyph); + void Contains(Glyph glyph); + CachedGlyphInfo this[Glyph glyph] { get; } + } +} diff --git a/Source/Utilities/Graphics/Text/TextBlock.cs b/Source/Utilities/Graphics/Text/TextBlock.cs index 570827b5..2c8df7e0 100644 --- a/Source/Utilities/Graphics/Text/TextBlock.cs +++ b/Source/Utilities/Graphics/Text/TextBlock.cs @@ -33,7 +33,7 @@ using System.Drawing; namespace OpenTK.Graphics.Text { // Uniquely identifies a block of text. This structure can be used to identify text blocks for caching. - struct TextBlock : IEquatable + struct TextBlock : IEquatable, IEnumerable { #region Fields @@ -77,6 +77,11 @@ namespace OpenTK.Graphics.Text return Text.GetHashCode() ^ Font.GetHashCode() ^ LayoutRectangle.GetHashCode() ^ Options.GetHashCode(); } + public Glyph this[int i] + { + get { return new Glyph(Text[i], Font); } + } + #endregion #region IEquatable Members @@ -91,5 +96,23 @@ namespace OpenTK.Graphics.Text } #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new GlyphEnumerator(Text, Font); + } + + #endregion + + #region IEnumerable Members + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return new GlyphEnumerator(Text, Font); + } + + #endregion } } diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index 86d5d8a2..bdabe00b 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -140,20 +140,6 @@ namespace OpenTK.Graphics throw new ArgumentNullException("font"); text_output.Print(new TextBlock(text, font, options, layoutRectangle), glyph_rasterizer, glyph_cache); - - //glyph_rasterizer.MeasureText(text, font, options, layoutRectangle, ref text_extents); - - //List vertices = new List(); - //List indices = new List(); - //PerformLayout(new TextBlock(text, font, layoutRectangle, options), text_extents, vertices, indices); - - //GL.Begin(BeginMode.Triangles); - //foreach (int i in indices) - //{ - // GL.TexCoord2(vertices[i + 1]); - // GL.Vertex2(vertices[i]); - //} - //GL.End(); } #endregion @@ -200,70 +186,5 @@ namespace OpenTK.Graphics #endregion #endregion - - #region Private Members - - #region PerformLayout - - void PerformLayout(TextBlock block, TextExtents extents, List vertices, List indices) - { - vertices.Clear(); - vertices.Capacity = 4 * block.Text.Length; - indices.Clear(); - indices.Capacity = 6 * block.Text.Length; - - float x_pos = 0, y_pos = 0; - RectangleF rect = new RectangleF(); - float char_width, char_height; - - // Every character comprises of 4 vertices, forming two triangles. We generate an index array which - // indexes vertices in a triangle-list fashion. - - int current = 0; - foreach (char c in block.Text) - { - if (c == '\n' || c == '\r') - continue; - else if (Char.IsWhiteSpace(c)) - { - current++; - continue; - } - else if (!glyph_cache.Contains(c, block.Font)) - glyph_cache.Add(c, block.Font); - - //font.GlyphData(c, out char_width, out char_height, out rect, out texture); - CachedGlyphInfo cache_info = glyph_cache[c, block.Font]; - RectangleF glyph_position = extents[current]; - - x_pos = glyph_position.X; - y_pos = glyph_position.Y; - char_width = glyph_position.Width; - char_height = glyph_position.Height; - - // Interleaved array: Vertex, TexCoord, Vertex, ... - vertices.Add(new Vector2(x_pos, y_pos)); // Vertex - vertices.Add(new Vector2(rect.Left, rect.Top)); // Texcoord - vertices.Add(new Vector2(x_pos, y_pos + char_height)); - vertices.Add(new Vector2(rect.Left, rect.Bottom)); - - vertices.Add(new Vector2(x_pos + char_width, y_pos + char_height)); - vertices.Add(new Vector2(rect.Right, rect.Bottom)); - vertices.Add(new Vector2(x_pos + char_width, y_pos)); - vertices.Add(new Vector2(rect.Right, rect.Top)); - - indices.Add(vertices.Count - 8); - indices.Add(vertices.Count - 6); - indices.Add(vertices.Count - 4); - - indices.Add(vertices.Count - 4); - indices.Add(vertices.Count - 2); - indices.Add(vertices.Count - 8); - } - } - - #endregion - - #endregion } }