From a57eb8f647c520c1446b030a20ea7940ba66c473 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Mon, 24 Nov 2008 16:43:56 +0000 Subject: [PATCH 02/53] First public commit of the new text renderer (WIP implementation). --- Source/Examples/OpenGL/JuliaSetFractal.cs | 30 +-- Source/Examples/Tests/MathSpeed.cs | 2 +- Source/Examples/Tutorial/Text.cs | 14 +- Source/Utilities/Fonts/Glyph.cs | 21 +- Source/Utilities/Fonts/TextPrinter.cs | 163 +++++++++++++- Source/Utilities/Fonts/TextPrinterOptions.cs | 14 ++ Source/Utilities/Graphics/CachedGlyphInfo.cs | 35 +++ .../Graphics/GraphicsResourceException.cs | 17 ++ .../Utilities/Graphics/IGraphicsResource.cs | 22 ++ .../Graphics/Text/GL1TextOutputProvider.cs | 84 +++++++ Source/Utilities/Graphics/Text/Glyph.cs | 117 ++++++++++ Source/Utilities/Graphics/Text/GlyphCache.cs | 100 +++++++++ Source/Utilities/Graphics/Text/GlyphPacker.cs | 208 ++++++++++++++++++ Source/Utilities/Graphics/Text/GlyphSheet.cs | 43 ++++ .../Graphics/Text/IGlyphRasterizer.cs | 17 ++ .../Graphics/Text/ITextOutputProvider.cs | 11 + Source/Utilities/Graphics/Text/TextBlock.cs | 68 ++++++ .../Graphics/Text/TextBlockComparer.cs | 24 ++ Source/Utilities/Graphics/Text/TextExtents.cs | 87 ++++++++ Source/Utilities/Graphics/TextureRegion2D.cs | 52 +++++ Source/Utilities/TexturePacker.cs | 7 +- 21 files changed, 1103 insertions(+), 33 deletions(-) create mode 100644 Source/Utilities/Fonts/TextPrinterOptions.cs create mode 100644 Source/Utilities/Graphics/CachedGlyphInfo.cs create mode 100644 Source/Utilities/Graphics/GraphicsResourceException.cs create mode 100644 Source/Utilities/Graphics/IGraphicsResource.cs create mode 100644 Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs create mode 100644 Source/Utilities/Graphics/Text/Glyph.cs create mode 100644 Source/Utilities/Graphics/Text/GlyphCache.cs create mode 100644 Source/Utilities/Graphics/Text/GlyphPacker.cs create mode 100644 Source/Utilities/Graphics/Text/GlyphSheet.cs create mode 100644 Source/Utilities/Graphics/Text/IGlyphRasterizer.cs create mode 100644 Source/Utilities/Graphics/Text/ITextOutputProvider.cs create mode 100644 Source/Utilities/Graphics/Text/TextBlock.cs create mode 100644 Source/Utilities/Graphics/Text/TextBlockComparer.cs create mode 100644 Source/Utilities/Graphics/Text/TextExtents.cs create mode 100644 Source/Utilities/Graphics/TextureRegion2D.cs diff --git a/Source/Examples/OpenGL/JuliaSetFractal.cs b/Source/Examples/OpenGL/JuliaSetFractal.cs index 85951792..2ea7add4 100644 --- a/Source/Examples/OpenGL/JuliaSetFractal.cs +++ b/Source/Examples/OpenGL/JuliaSetFractal.cs @@ -164,30 +164,30 @@ namespace Examples.Tutorial PixelType.UnsignedByte, data.Scan0); bitmap.UnlockBits(data); } - #endregion Textures - + #endregion Textures + Keyboard.KeyUp += KeyUp; } - - int i = 0; - void KeyUp(OpenTK.Input.KeyboardDevice sender, OpenTK.Input.Key e) - { - if (e == OpenTK.Input.Key.F12) - { + + int i = 0; + void KeyUp(OpenTK.Input.KeyboardDevice sender, OpenTK.Input.Key e) + { + if (e == OpenTK.Input.Key.F12) + { Bitmap bmp = new Bitmap(this.Width, this.Height); System.Drawing.Imaging.BitmapData data = - bmp.LockBits(new Rectangle(0, 0, this.Width, this.Height), + bmp.LockBits(new Rectangle(0, 0, this.Width, this.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); - GL.ReadPixels(0, 0, this.Width, this.Height, - OpenTK.Graphics.PixelFormat.Bgr, + GL.ReadPixels(0, 0, this.Width, this.Height, + OpenTK.Graphics.PixelFormat.Bgr, OpenTK.Graphics.PixelType.UnsignedByte, data.Scan0); bmp.UnlockBits(data); bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); - bmp.Save("Screenshot" + (i++).ToString() + ".png", ImageFormat.Png); - } - } + bmp.Save("Screenshot" + (i++).ToString() + ".png", ImageFormat.Png); + } + } #endregion @@ -241,7 +241,7 @@ namespace Examples.Tutorial if (Keyboard[OpenTK.Input.Key.Escape]) { this.Exit(); - } + } } #endregion diff --git a/Source/Examples/Tests/MathSpeed.cs b/Source/Examples/Tests/MathSpeed.cs index d4017abc..14efa5c6 100644 --- a/Source/Examples/Tests/MathSpeed.cs +++ b/Source/Examples/Tests/MathSpeed.cs @@ -16,7 +16,7 @@ namespace Examples.Tests public class MathSpeed { public static void Main() - { + { /* Stopwatch watch = new Stopwatch(); diff --git a/Source/Examples/Tutorial/Text.cs b/Source/Examples/Tutorial/Text.cs index cabc7cf2..266779f5 100644 --- a/Source/Examples/Tutorial/Text.cs +++ b/Source/Examples/Tutorial/Text.cs @@ -23,10 +23,11 @@ namespace Examples.Tutorial [Example("Text", ExampleCategory.Tutorial, 4)] public class Text : GameWindow { - TextureFont serif = new TextureFont(new Font(FontFamily.GenericSerif, 24.0f)); + Font serif2 = new Font(FontFamily.GenericSerif, 14.0f); + TextureFont serif = new TextureFont(new Font(FontFamily.GenericSerif, 12.0f)); TextureFont sans = new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f)); TextHandle poem_handle; - ITextPrinter text = new TextPrinter(); + TextPrinter text = new TextPrinter(); string poem = new StreamReader("Data/Poem.txt").ReadToEnd(); int lines; // How many lines the poem contains. @@ -125,11 +126,14 @@ namespace Examples.Tutorial // used in 2d graphics, and is necessary for achieving pixel-perfect glyph rendering. // TextPrinter.End() restores your previous projection/modelview matrices. text.Begin(); - GL.Color3(Color.LightBlue); - text.Draw((1.0 / e.Time).ToString("F2"), sans); + //GL.Color3(Color.LightBlue); + //text.Draw((1.0 / e.Time).ToString("F2"), sans); GL.Translate(0.0f, current_position, 0.0f); GL.Color3(Color.White); - text.Draw(poem_handle); + //text.Draw(poem_handle); + //text.Draw(poem, serif); + //GL.BindTexture(TextureTarget.Texture2D, 1); + text.Print(poem, serif2); text.End(); SwapBuffers(); diff --git a/Source/Utilities/Fonts/Glyph.cs b/Source/Utilities/Fonts/Glyph.cs index 25470c65..c64acfe5 100644 --- a/Source/Utilities/Fonts/Glyph.cs +++ b/Source/Utilities/Fonts/Glyph.cs @@ -111,12 +111,29 @@ namespace OpenTK.Graphics /// A System.Int32 containing a hashcode that uniquely identifies this Glyph. public override int GetHashCode() { - //return character.GetHashCode() ^ font.Style.GetHashCode() ^ font.Size.GetHashCode() ^ font.Unit.GetHashCode(); return character.GetHashCode() ^ font.GetHashCode() ^ size.GetHashCode(); } #endregion + #region public SizeF Size + + /// + /// Gets the size of this Glyph. + /// + public SizeF Size { get { return size; } } + + #endregion + + #region public RectangleF Rectangle + + /// + /// Gets the bounding box of this Glyph. + /// + public RectangleF Rectangle { get { return new RectangleF(PointF.Empty, Size); } } + + #endregion + #endregion #region --- IPackable Members --- @@ -154,7 +171,7 @@ namespace OpenTK.Graphics /// True if both Glyphs represent the same character of the same Font, false otherwise. public bool Equals(Glyph other) { - return Character == other.Character && Font == other.Font; + return Character == other.Character && Font == other.Font && Size == other.Size; } #endregion diff --git a/Source/Utilities/Fonts/TextPrinter.cs b/Source/Utilities/Fonts/TextPrinter.cs index b59a5b0b..54613f94 100644 --- a/Source/Utilities/Fonts/TextPrinter.cs +++ b/Source/Utilities/Fonts/TextPrinter.cs @@ -12,11 +12,12 @@ using System.Text; using System.Drawing; using System.Text.RegularExpressions; using System.Runtime.InteropServices; +using System.Diagnostics; using OpenTK.Math; -using OpenTK.Graphics.OpenGL; -using OpenTK.Graphics.OpenGL.Enums; -using System.Diagnostics; +using OpenTK.Graphics; +using OpenTK.Graphics.Text; +using OpenTK.Platform; namespace OpenTK.Fonts { } @@ -25,7 +26,7 @@ namespace OpenTK.Graphics /// /// Provides methods to perform layout and print hardware accelerated text. /// - public class TextPrinter : ITextPrinter + public sealed class TextPrinter : ITextPrinter { //static Regex break_point = new Regex("[ .,/*-+?\\!=]", RegexOptions.Compiled | RegexOptions.IgnoreCase); //static char[] split_chars = new char[] @@ -42,11 +43,6 @@ namespace OpenTK.Graphics #region --- Constructors --- - /// - /// Constructs a new TextPrinter object. - /// - public TextPrinter() { } - public TextPrinter(ITextPrinterImplementation implementation) { if (implementation == null) @@ -359,5 +355,154 @@ namespace OpenTK.Graphics #endregion #endregion + + #region New Implementation + + #region Fields + + Dictionary font_cache = new Dictionary(); + + GlyphCache glyph_cache; + IGlyphRasterizer glyph_rasterizer; + ITextOutputProvider text_output; + + //TextExtents text_extents = new TextExtents(); + + #endregion + + #region Constructors + + /// + /// Constructs a new TextPrinter object. + /// + public TextPrinter() + : this(null, null) + { + } + + TextPrinter(IGlyphRasterizer rasterizer, ITextOutputProvider output/*, IGlyphCacheProvider, ITextOutputProvider */) + { + if (rasterizer == null) + rasterizer = new GdiPlusGlyphRasterizer(); + + if (output == null) + output = new GL1TextOutputProvider(); + + glyph_rasterizer = rasterizer; + glyph_cache = new GlyphCache(rasterizer); + text_output = output; + } + + #endregion + + #region Public Members + + #region Print + + public void Print(string text, Font font) + { + Print(text, font, 0, RectangleF.Empty); + } + + public void Print(string text, Font font, TextPrinterOptions options) + { + Print(text, font, options, RectangleF.Empty); + } + + public void Print(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle) + { + if (String.IsNullOrEmpty(text)) + return; + + if (font == null) + 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 + + #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 + + #endregion } } diff --git a/Source/Utilities/Fonts/TextPrinterOptions.cs b/Source/Utilities/Fonts/TextPrinterOptions.cs new file mode 100644 index 00000000..55fb7dd0 --- /dev/null +++ b/Source/Utilities/Fonts/TextPrinterOptions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics +{ + [Flags] + public enum TextPrinterOptions + { + NoCache = 1, + RightToLeft = 2, + Vertical = 4, + } +} diff --git a/Source/Utilities/Graphics/CachedGlyphInfo.cs b/Source/Utilities/Graphics/CachedGlyphInfo.cs new file mode 100644 index 00000000..e5154f18 --- /dev/null +++ b/Source/Utilities/Graphics/CachedGlyphInfo.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics +{ + struct CachedGlyphInfo + { + public readonly AlphaTexture2D Texture; + public readonly RectangleF RectangleNormalized; + public Rectangle Rectangle + { + get + { + return new Rectangle( + (int)(RectangleNormalized.X * Texture.Width), + (int)(RectangleNormalized.Y * Texture.Height), + (int)(RectangleNormalized.Width * Texture.Width), + (int)(RectangleNormalized.Height * Texture.Height)); + } + } + + // Rect denotes the absolute position of the glyph in the texture [0, Texture.Width], [0, Texture.Height]. + public CachedGlyphInfo(AlphaTexture2D texture, Rectangle rect) + { + Texture = texture; + RectangleNormalized = new RectangleF( + rect.X / (float)texture.Width, + rect.Y / (float)texture.Height, + rect.Width / (float)texture.Width, + rect.Height / (float)texture.Height); + } + } +} diff --git a/Source/Utilities/Graphics/GraphicsResourceException.cs b/Source/Utilities/Graphics/GraphicsResourceException.cs new file mode 100644 index 00000000..8a7aa297 --- /dev/null +++ b/Source/Utilities/Graphics/GraphicsResourceException.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics +{ + /// + /// Represents exceptions related to IGraphicsResources. + /// + public class GraphicsResourceException : Exception + { + /// Constructs a new GraphicsResourceException. + public GraphicsResourceException() : base() { } + /// Constructs a new string with the specified error message. + public GraphicsResourceException(string message) : base(message) { } + } +} diff --git a/Source/Utilities/Graphics/IGraphicsResource.cs b/Source/Utilities/Graphics/IGraphicsResource.cs new file mode 100644 index 00000000..7d5d4987 --- /dev/null +++ b/Source/Utilities/Graphics/IGraphicsResource.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics +{ + /// + /// Defines a common interface to all OpenGL resources. + /// + interface IGraphicsResource : IDisposable + { + /// + /// Gets the GraphicsContext that owns this resource. + /// + GraphicsContext Context { get; } + + /// + /// Gets the Id of this IGraphicsResource. + /// + int Id { get; } + } +} diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs new file mode 100644 index 00000000..5f00f8ea --- /dev/null +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics.Text +{ + class GL1TextOutputProvider : ITextOutputProvider + { + #region Constructors + + public GL1TextOutputProvider() { } + + #endregion + + #region ITextOutputProvider Members + + public void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache) + { + 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, 1); + + //GL.Begin(BeginMode.Quads); + + //GL.TexCoord2(0, 0); + //GL.Vertex2(0, 0); + //GL.TexCoord2(1, 0); + //GL.Vertex2(256, 0); + //GL.TexCoord2(1, 1); + //GL.Vertex2(256, 256); + //GL.TexCoord2(0, 1); + //GL.Vertex2(0, 256); + + //GL.End(); + + //GL.Translate(0, 256, 0); + + //GL.Disable(EnableCap.Texture2D); + //GL.BindTexture(TextureTarget.Texture2D, 1); + GL.Begin(BeginMode.Triangles); + + int current = 0; + foreach (char c in block.Text) + { + if (c == '\n' || c == '\r') + continue; + else if (Char.IsWhiteSpace(c)) + { + current++; + continue; + } + + CachedGlyphInfo info = cache[c, block.Font]; + RectangleF position = extents[current++]; + + position.Size = info.Rectangle.Size; + + // Interleaved array: Vertex, TexCoord, Vertex, ... + GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Top); + GL.Vertex2(position.Left, position.Top); + GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom); + GL.Vertex2(position.Left, position.Bottom); + GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom); + GL.Vertex2(position.Right, position.Bottom); + + GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom); + GL.Vertex2(position.Right, position.Bottom); + GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Top); + GL.Vertex2(position.Right, position.Top); + GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Top); + GL.Vertex2(position.Left, position.Top); + } + + GL.End(); + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/Glyph.cs b/Source/Utilities/Graphics/Text/Glyph.cs new file mode 100644 index 00000000..aea2403b --- /dev/null +++ b/Source/Utilities/Graphics/Text/Glyph.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics.Text +{ + struct Glyph : IEquatable + { + char character; + Font font; + + #region Constructors + + /// + /// Constructs a new Glyph that represents the given character and Font. + /// + /// The character to represent. + /// The Font of the character. + public Glyph(char c, Font font) + { + if (font == null) + throw new ArgumentNullException("font"); + character = c; + this.font = font; + } + + #endregion + + #region --- Public Methods --- + + #region public char Character + + /// + /// Gets the character represented by this Glyph. + /// + public char Character + { + get { return character; } + private set { character = value; } + } + + #endregion + + #region public Font Font + + /// + /// Gets the Font of this Glyph. + /// + public Font Font + { + get { return font; } + private set + { + if (value == null) + throw new ArgumentNullException("Font", "Glyph font cannot be null"); + + font = value; + } + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Checks whether the given object is equal (memberwise) to the current Glyph. + /// + /// The obj to check. + /// True, if the object is identical to the current Glyph. + public override bool Equals(object obj) + { + if (obj is Glyph) + return this.Equals((Glyph)obj); + return base.Equals(obj); + } + + #endregion + + #region public override string ToString() + + /// + /// Describes this Glyph object. + /// + /// Returns a System.String describing this Glyph. + public override string ToString() + { + return String.Format("'{0}', {1} {2}, {3} {4}", Character, Font.Name, font.Style, font.Size, font.Unit); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Calculates the hashcode for this Glyph. + /// + /// A System.Int32 containing a hashcode that uniquely identifies this Glyph. + public override int GetHashCode() + { + return character.GetHashCode() ^ font.GetHashCode(); + } + + #endregion + + #endregion + + #region IEquatable Members + + public bool Equals(Glyph other) + { + return Character == other.Character && Font == other.Font; + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/GlyphCache.cs b/Source/Utilities/Graphics/Text/GlyphCache.cs new file mode 100644 index 00000000..e862df9e --- /dev/null +++ b/Source/Utilities/Graphics/Text/GlyphCache.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +using OpenTK.Graphics; +using System.Diagnostics; + +namespace OpenTK.Graphics.Text +{ + class GlyphCache + { + #region Fields + + IGlyphRasterizer rasterizer; + List sheets = new List(); + Bitmap bmp = new Bitmap(256, 256); + + Dictionary cached_glyphs = new Dictionary(); + + #endregion + + #region Constructors + + public GlyphCache(IGlyphRasterizer rasterizer) + { + if (rasterizer == null) + throw new ArgumentNullException("rasterizer"); + + this.rasterizer = rasterizer; + sheets.Add(new GlyphSheet()); + } + + #endregion + + #region Public Members + + public void Add(char c, Font font) + { + Glyph glyph = new Glyph(c, font); + bool inserted = false; + + using (Bitmap bmp = rasterizer.Rasterize(glyph)) + { + foreach (GlyphSheet sheet in sheets) + { + try + { + InsertGlyph(glyph, bmp, sheet); + inserted = true; + break; + } + catch (TexturePackerFullException) + { + } + } + + if (!inserted) + { + GlyphSheet sheet = new GlyphSheet(); + sheets.Add(sheet); + InsertGlyph(glyph, bmp, sheet); + } + } + } + + 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)); + } + + 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)]; + } + } + + public CachedGlyphInfo this[Glyph glyph] + { + get + { + return cached_glyphs[glyph]; + } + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/GlyphPacker.cs b/Source/Utilities/Graphics/Text/GlyphPacker.cs new file mode 100644 index 00000000..1a492aa5 --- /dev/null +++ b/Source/Utilities/Graphics/Text/GlyphPacker.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics.Text +{ + class GlyphPacker + { + Node root; + + #region --- Constructors --- + + public GlyphPacker(int width, int height) + { + if (width <= 0) + throw new ArgumentOutOfRangeException("width", width, "Must be greater than zero."); + if (height <= 0) + throw new ArgumentOutOfRangeException("height", height, "Must be greater than zero."); + + root = new Node(); + root.Rectangle = new Rectangle(0, 0, width, width); + } + + #endregion + + #region --- Public Methods --- + + #region public Rectangle Add(Rectangle boundingBox) + + /// + /// Adds boundingBox to the GlyphPacker. + /// + /// The bounding box of the item to pack. + /// A System.Drawing.Rectangle containing the coordinates of the packed item. + /// Occurs if the item is larger than the available TexturePacker area + /// Occurs if the item already exists in the TexturePacker. + public Rectangle Add(Rectangle boundingBox) + { + if (!root.Rectangle.Contains(boundingBox)) + throw new InvalidOperationException("The item is too large for this TexturePacker"); + + Node node; + node = root.Insert(boundingBox); + + // Tree is full and insertion failed: + if (node == null) + throw new TexturePackerFullException(); + + return node.Rectangle; + } + + #endregion + + #region public Rectangle Add(RectangleF boundingBox) + + /// + /// Rounds boundingBox to the largest integer and adds the resulting Rectangle to the GlyphPacker. + /// + /// The bounding box of the item to pack. + /// A System.Drawing.Rectangle containing the coordinates of the packed item. + /// Occurs if the item is larger than the available TexturePacker area + /// Occurs if the item already exists in the TexturePacker. + public Rectangle Add(RectangleF boundingBox) + { + Rectangle bbox = new Rectangle( + (int)boundingBox.X, (int)boundingBox.Y, + (int)(boundingBox.Width + 0.5f), (int)(boundingBox.Height + 0.5f)); + + return Add(bbox); + } + + #endregion + + #region public void Clear() + + /// + /// Discards all packed items. + /// + public void Clear() + { + root.Clear(); + } + + #endregion + + #region public void ChangeSize(int new_width, int new_height) + + /// + /// Changes the dimensions of the TexturePacker surface. + /// + /// The new width of the TexturePacker surface. + /// The new height of the TexturePacker surface. + /// Changing the size of the TexturePacker surface will implicitly call TexturePacker.Clear(). + /// + public void ChangeSize(int new_width, int new_height) + { + throw new NotImplementedException(); + } + + #endregion + + #endregion + + #region Node + + class Node + { + public Node() + { + } + + Node left, right; + Rectangle rect; + bool occupied; + + public Rectangle Rectangle { get { return rect; } set { rect = value; } } + public Node Left { get { return left; } set { left = value; } } + public Node Right { get { return right; } set { right = value; } } + + #region --- Constructor --- + + public bool Leaf + { + get { return left == null && right == null; } + } + + #endregion + + #region Node Insert(Rectangle bbox) + + public Node Insert( Rectangle bbox) + { + if (!this.Leaf) + { + // Recurse towards left child, and if that fails, towards the right. + Node new_node = left.Insert(bbox); + return new_node ?? right.Insert(bbox); + } + else + { + // We have recursed to a leaf. + + // If it is not empty go back. + if (occupied) + return null; + + // If this leaf is too small go back. + if (rect.Width < bbox.Width || rect.Height < bbox.Height) + return null; + + // If this leaf is the right size, insert here. + if (rect.Width == bbox.Width && rect.Height == bbox.Height) + { + occupied = true; + return this; + } + + // This leaf is too large, split it up. We'll decide which way to split + // by checking the width and height difference between this rectangle and + // out item's bounding box. If the width difference is larger, we'll split + // horizontaly, else verticaly. + left = new Node(); + right = new Node(); + + int dw = this.rect.Width - bbox.Width + 1; + int dh = this.rect.Height - bbox.Height + 1; + + if (dw > dh) + { + left.rect = new Rectangle(rect.Left, rect.Top, bbox.Width, rect.Height); + right.rect = new Rectangle(rect.Left + bbox.Width, rect.Top, rect.Width - bbox.Width, rect.Height); + } + else + { + left.rect = new Rectangle(rect.Left, rect.Top, rect.Width, bbox.Height); + right.rect = new Rectangle(rect.Left, rect.Top + bbox.Height, rect.Width, rect.Height - bbox.Height); + } + + return left.Insert(bbox); + } + } + + #endregion + + #region public void Clear() + + public void Clear() + { + if (left != null) + left.Clear(); + if (right != null) + right.Clear(); + + left = right = null; + } + + #endregion + } + + #endregion + } + + class TexturePackerFullException : Exception + { + public TexturePackerFullException() : base("There is not enough space to add this item. Consider calling the Clear() method.") { } + } +} diff --git a/Source/Utilities/Graphics/Text/GlyphSheet.cs b/Source/Utilities/Graphics/Text/GlyphSheet.cs new file mode 100644 index 00000000..1a709eb2 --- /dev/null +++ b/Source/Utilities/Graphics/Text/GlyphSheet.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics.Text +{ + class GlyphSheet + { + #region Fields + + AlphaTexture2D texture; + GlyphPacker packer; + + #endregion + + #region Constructors + + public GlyphSheet() + { + Texture = new AlphaTexture2D(256, 256); + Packer = new GlyphPacker(256, 256); + } + + #endregion + + #region Public Members + + public AlphaTexture2D Texture + { + get { return texture; } + private set { texture = value; } + } + + public GlyphPacker Packer + { + get { return packer; } + private set { packer = value; } + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs new file mode 100644 index 00000000..f8b2d2e8 --- /dev/null +++ b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +using OpenTK.Graphics.Text; + +namespace OpenTK.Graphics.Text +{ + interface IGlyphRasterizer + { + Bitmap Rasterize(Glyph glyph); + //void Rasterize(Glyph glyph, ref Bitmap bmp); + TextExtents MeasureText(TextBlock block); + RectangleF MeasureGlyph(Glyph glyph); + } +} diff --git a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs new file mode 100644 index 00000000..4090d0e8 --- /dev/null +++ b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics.Text +{ + interface ITextOutputProvider + { + void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache); + } +} diff --git a/Source/Utilities/Graphics/Text/TextBlock.cs b/Source/Utilities/Graphics/Text/TextBlock.cs new file mode 100644 index 00000000..ed235cec --- /dev/null +++ b/Source/Utilities/Graphics/Text/TextBlock.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; +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 + { + #region Fields + + public readonly string Text; + + public readonly Font Font; + + public readonly RectangleF LayoutRectangle; + + public readonly TextPrinterOptions Options; + + public int UsageCount; // Used to identify old and unused blocks of text. + + #endregion + + #region Constructors + + public TextBlock(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle) + { + Text = text; + Font = font; + LayoutRectangle = layoutRectangle; + Options = options; + UsageCount = 0; + } + + #endregion + + #region Public Members + + public override bool Equals(object obj) + { + if (!(obj is TextBlock)) + return false; + + return Equals((TextBlock)obj); + } + + public override int GetHashCode() + { + return Text.GetHashCode() ^ Font.GetHashCode() ^ LayoutRectangle.GetHashCode() ^ Options.GetHashCode(); + } + + #endregion + + #region IEquatable Members + + public bool Equals(TextBlock other) + { + return + Text == other.Text && + Font == other.Font && + LayoutRectangle == other.LayoutRectangle && + Options == other.Options; + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/TextBlockComparer.cs b/Source/Utilities/Graphics/Text/TextBlockComparer.cs new file mode 100644 index 00000000..524ba106 --- /dev/null +++ b/Source/Utilities/Graphics/Text/TextBlockComparer.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics.Text +{ + class TextBlockComparer : IComparer + { + #region Constructors + + public TextBlockComparer() { } + + #endregion + + #region IComparer Members + + public int Compare(TextBlock x, TextBlock y) + { + return x.UsageCount.CompareTo(y.UsageCount); + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/TextExtents.cs b/Source/Utilities/Graphics/Text/TextExtents.cs new file mode 100644 index 00000000..98ae31bc --- /dev/null +++ b/Source/Utilities/Graphics/Text/TextExtents.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics.Text +{ + // Holds layout information about a TextBlock. + public struct TextExtents + { + #region Fields + + RectangleF text_extents; + List glyph_extents; + + #endregion + + #region Constructors + + public TextExtents(RectangleF bbox) + : this(bbox, null) + { + } + + public TextExtents(RectangleF bbox, IEnumerable glyphExtents) + : this() + { + BoundingBox = bbox; + + if (glyphExtents != null) + AddRange(glyphExtents); + } + + #endregion + + #region Public Members + + public RectangleF BoundingBox + { + get { return text_extents; } + internal set { text_extents = value; } + } + + public RectangleF this[int i] + { + get { return (GlyphExtents as List)[i]; } + internal set { (GlyphExtents as List)[i] = value; } + } + + public IEnumerable GlyphExtents + { + get + { + if (glyph_extents == null) + glyph_extents = new List(); + return (IEnumerable)glyph_extents; + } + } + + public int Count + { + get { return (GlyphExtents as List).Count; } + } + + #endregion + + #region Internal Members + + internal void Add(RectangleF glyphExtent) + { + (GlyphExtents as List).Add(glyphExtent); + } + + internal void AddRange(IEnumerable glyphExtents) + { + (GlyphExtents as List).AddRange(glyphExtents); + } + + internal void Clear() + { + BoundingBox = RectangleF.Empty; + (GlyphExtents as List).Clear(); + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/TextureRegion2D.cs b/Source/Utilities/Graphics/TextureRegion2D.cs new file mode 100644 index 00000000..d44969f4 --- /dev/null +++ b/Source/Utilities/Graphics/TextureRegion2D.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics +{ + abstract class TextureRegion2D + { + Rectangle rectangle; + + public Rectangle Rectangle { get { return rectangle; } protected set { rectangle = value; } } + } + + /// + /// Holds part or the whole of a 2d OpenGL texture. + /// + class TextureRegion2D : TextureRegion2D where T : struct + { + #region Fields + + T[,] data; + + #endregion + + #region Constructors + + internal TextureRegion2D(Rectangle rect) + { + data = new T[rect.Width, rect.Height]; + Rectangle = rect; + } + + #endregion + + #region Public Members + + public T this[int x, int y] + { + get { return data[x, y]; } + set { data[x, y] = value; } + } + + #endregion + + #region Internal Members + + internal T[,] Data { get { return data; } } + + #endregion + } +} diff --git a/Source/Utilities/TexturePacker.cs b/Source/Utilities/TexturePacker.cs index ec44aa55..acffc12e 100644 --- a/Source/Utilities/TexturePacker.cs +++ b/Source/Utilities/TexturePacker.cs @@ -54,7 +54,7 @@ namespace OpenTK // Tree is full and insertion failed: if (node == null) - throw new InvalidOperationException("There is not enough space to add this item. Consider calling the Clear() method."); + throw new TexturePackerFullException(); //items.Add(item, node); rect = node.Rect; @@ -193,4 +193,9 @@ namespace OpenTK #endregion } + + class TexturePackerFullException : Exception + { + public TexturePackerFullException() : base("There is not enough space to add this item. Consider calling the Clear() method.") { } + } } From e3535cdbb1933abc2245ce976e9e0a3a5573c436 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Mon, 24 Nov 2008 17:55:34 +0000 Subject: [PATCH 03/53] Use 16pt font (looks better). --- Source/Examples/Tutorial/Text.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Examples/Tutorial/Text.cs b/Source/Examples/Tutorial/Text.cs index 266779f5..0fd3cdd5 100644 --- a/Source/Examples/Tutorial/Text.cs +++ b/Source/Examples/Tutorial/Text.cs @@ -23,7 +23,7 @@ namespace Examples.Tutorial [Example("Text", ExampleCategory.Tutorial, 4)] public class Text : GameWindow { - Font serif2 = new Font(FontFamily.GenericSerif, 14.0f); + Font serif2 = new Font(FontFamily.GenericSerif, 16.0f); TextureFont serif = new TextureFont(new Font(FontFamily.GenericSerif, 12.0f)); TextureFont sans = new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f)); TextHandle poem_handle; From 72e1216a31c8878eb6c5fab2736f6dee59b9432f Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Mon, 24 Nov 2008 18:02:19 +0000 Subject: [PATCH 04/53] Testing hack (hardcode texture #2). --- Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index 5f00f8ea..78787978 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -23,7 +23,7 @@ namespace OpenTK.Graphics.Text if (c != '\n' && c != '\r' && !Char.IsWhiteSpace(c) && !cache.Contains(c, block.Font)) cache.Add(c, block.Font); - GL.BindTexture(TextureTarget.Texture2D, 1); + GL.BindTexture(TextureTarget.Texture2D, 2); //GL.Begin(BeginMode.Quads); @@ -40,8 +40,6 @@ namespace OpenTK.Graphics.Text //GL.Translate(0, 256, 0); - //GL.Disable(EnableCap.Texture2D); - //GL.BindTexture(TextureTarget.Texture2D, 1); GL.Begin(BeginMode.Triangles); int current = 0; From 5e449dabd4cc4ed16af9f8d1cf4b7db990d634aa Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Mon, 24 Nov 2008 18:02:57 +0000 Subject: [PATCH 05/53] Add 2 pixels of space between packed glyphs, to avoid rendering artifacts. --- Source/Utilities/Graphics/Text/GlyphPacker.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Utilities/Graphics/Text/GlyphPacker.cs b/Source/Utilities/Graphics/Text/GlyphPacker.cs index 1a492aa5..90e9c4ce 100644 --- a/Source/Utilities/Graphics/Text/GlyphPacker.cs +++ b/Source/Utilities/Graphics/Text/GlyphPacker.cs @@ -41,13 +41,17 @@ namespace OpenTK.Graphics.Text throw new InvalidOperationException("The item is too large for this TexturePacker"); Node node; + // Increase size so that the glyphs do not touch each other (to avoid rendering artifacts). + boundingBox.Width += 2; + boundingBox.Height += 2; node = root.Insert(boundingBox); // Tree is full and insertion failed: if (node == null) throw new TexturePackerFullException(); - return node.Rectangle; + return new Rectangle(node.Rectangle.X, node.Rectangle.Y, node.Rectangle.Width - 2, node.Rectangle.Height - 2); + //return node.Rectangle; } #endregion From 18cb4d24326e2b5d59b0d51483afaf5417d719fd Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Mon, 24 Nov 2008 18:03:47 +0000 Subject: [PATCH 06/53] Added missing files from working copy. --- Source/Utilities/Graphics/AlphaTexture2D.cs | 201 +++++++++++++ .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 268 ++++++++++++++++++ 2 files changed, 469 insertions(+) create mode 100644 Source/Utilities/Graphics/AlphaTexture2D.cs create mode 100644 Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs diff --git a/Source/Utilities/Graphics/AlphaTexture2D.cs b/Source/Utilities/Graphics/AlphaTexture2D.cs new file mode 100644 index 00000000..d4db7676 --- /dev/null +++ b/Source/Utilities/Graphics/AlphaTexture2D.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Drawing.Imaging; + +namespace OpenTK.Graphics +{ + /// + /// Encapsulates an OpenGL texture. + /// + class AlphaTexture2D : IGraphicsResource + { + #region Fields + + GraphicsContext context; + int id; + int width, height; + bool disposed; + + #endregion + + #region Constructors + + /// + /// Constructs a new Texture. + /// + public AlphaTexture2D(int width, int height) + { + Width = width; + Height = height; + } + + #endregion + + #region IGraphicsResource Members + + GraphicsContext IGraphicsResource.Context { get { return context; } } + + int IGraphicsResource.Id + { + get + { + if (id == 0) + { + GraphicsContext.Assert(); + context = GraphicsContext.CurrentContext; + + id = GL.GenTexture(); + if (id == 0) + throw new GraphicsResourceException(String.Format("Texture creation failed, (Error: {0})", GL.GetError())); + + // Ensure the texture is allocated. + GL.BindTexture(TextureTarget.Texture2D, id); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); + if (GL.SupportsExtension("Version12")) + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge); + } + else + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Clamp); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Clamp); + } + + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Alpha, Width, Height, 0, + OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); + } + + return id; + } + } + + #endregion + + #region Public Members + + #region public int Width + + /// Gets the width of the texture. + public int Width { get { return width; } private set { width = value; } } + + #endregion + + #region public int Height + + /// Gets the height of the texture. + public int Height { get { return height; } private set { height = value; } } + + #endregion + + #region WriteRegion + + public void WriteRegion(Rectangle source, Rectangle target, int mipLevel, Bitmap bitmap) + { + if (bitmap == null) + throw new ArgumentNullException("data"); + + GraphicsUnit unit = GraphicsUnit.Pixel; + + if (!bitmap.GetBounds(ref unit).Contains(source)) + throw new InvalidOperationException("The source Rectangle is larger than the Bitmap."); + + if (mipLevel < 0) + throw new ArgumentOutOfRangeException("mipLevel"); + + Bind(); + + BitmapData data = bitmap.LockBits(source, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + GL.PushClientAttrib(ClientAttribMask.ClientPixelStoreBit); + try + { + GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); + GL.PixelStore(PixelStoreParameter.UnpackRowLength, bitmap.Width); + GL.TexSubImage2D(TextureTarget.Texture2D, mipLevel, + target.Left, target.Top, + target.Width, target.Height, + OpenTK.Graphics.PixelFormat.Rgba, + PixelType.UnsignedByte, data.Scan0); + } + finally + { + GL.PopClientAttrib(); + } + + bitmap.UnlockBits(data); + } + + public void WriteRegion(TextureRegion2D region, int mipLevel) + { + if (mipLevel < 0) + throw new ArgumentOutOfRangeException("miplevel"); + + GL.TexSubImage2D(TextureTarget.Texture2D, mipLevel, + region.Rectangle.X, region.Rectangle.Y, + region.Rectangle.Width, region.Rectangle.Height, + PixelFormat.Bgra, PixelType.UnsignedByte, region); + } + + #endregion + + #region ReadRegion + + public TextureRegion2D ReadRegion(Rectangle rect, int mipLevel) + { + if (mipLevel < 0) + throw new ArgumentOutOfRangeException("miplevel"); + + TextureRegion2D region = new TextureRegion2D(rect); + + GL.GetTexImage(TextureTarget.Texture2D, mipLevel, PixelFormat.Bgra, PixelType.UnsignedByte, region.Data); + + return region; + } + + #endregion + + #region Bind + + public void Bind() + { + GL.BindTexture(TextureTarget.Texture2D, (this as IGraphicsResource).Id); + } + + #endregion + + #endregion + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool manual) + { + if (!disposed) + { + if (manual) + { + GL.DeleteTexture(id); + } + disposed = true; + } + } + + ~AlphaTexture2D() + { + GraphicsContext context = (this as IGraphicsResource).Context; + if (context != null) + (context as IGraphicsContextInternal).RegisterForDisposal(this); + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs new file mode 100644 index 00000000..92b13e6d --- /dev/null +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Drawing.Text; + +using OpenTK.Graphics.Text; +using OpenTK.Platform; +using System.Diagnostics; + +namespace OpenTK.Graphics.Text +{ + class GdiPlusGlyphRasterizer : IGlyphRasterizer + { + #region Fields + + Dictionary block_cache = new Dictionary(); + System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(new Bitmap(1, 1)); + + IntPtr[] regions = new IntPtr[GdiPlus.MaxMeasurableCharacterRanges]; + CharacterRange[] characterRanges = new CharacterRange[GdiPlus.MaxMeasurableCharacterRanges]; + + TextExtents extents = new TextExtents(); + + // Check the constructor, too, for additional flags. + static readonly StringFormat default_string_format = StringFormat.GenericTypographic; + static readonly StringFormat load_glyph_string_format = StringFormat.GenericDefault; + + static readonly char[] newline_characters = new char[] { '\n', '\r' }; + + #endregion + + #region Constructors + + static GdiPlusGlyphRasterizer() + { + default_string_format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; + } + + public GdiPlusGlyphRasterizer() + { } + + #endregion + + #region IGlyphRasterizer Members + + #region Rasterize + + 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)) + { + // Small sizes look blurry without gridfitting, so turn that on. + if (glyph.Font.Size <= 18.0f) + gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + else + gfx.TextRenderingHint = TextRenderingHint.AntiAlias; + + gfx.Clear(Color.Transparent); + gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty); + + Rectangle tight_rect = FindEdges(bmp); + Bitmap tight_glyph = bmp.Clone(tight_rect, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + //new Bitmap(tight_rect.Width, tight_rect.Height); + //return bmp.Clone(FindEdges(bmp), System.Drawing.Imaging.PixelFormat.Format32bppArgb); + return tight_glyph; + } + } + + #endregion + + #region MeasureText + + //public RectangleF MeasureText(TextBlock block) + //{ + // return MeasureText(block, ref extents); + //} + + public TextExtents MeasureText(TextBlock block) + { + // First, check if we have cached this text block. Do not use block_cache.TryGetValue, to avoid thrashing + // the user's TextBlockExtents struct. + if (block_cache.ContainsKey(block)) + return block_cache[block]; + + // If this block is not cached, we have to measure it and place it in the cache. + MeasureTextExtents(block, ref extents); + if ((block.Options & TextPrinterOptions.NoCache) == 0) + block_cache.Add(block, new TextExtents(extents.BoundingBox, extents.GlyphExtents)); + + return extents; + } + + #endregion + + #region MeasureGlyph + + public RectangleF MeasureGlyph(Glyph glyph) + { + using (Bitmap bmp = Rasterize(glyph)) + { + return FindEdges(bmp); + } + } + + #endregion + + #endregion + + #region Private Members + + #region MeasureTextExtents + + void MeasureTextExtents(TextBlock block, ref TextExtents extents) + { + // Todo: Parse layout options: + StringFormat format = default_string_format; + + extents.Clear(); + + PointF origin = PointF.Empty; + SizeF size = SizeF.Empty; + + IntPtr native_graphics = GdiPlus.GetNativeGraphics(graphics); + IntPtr native_font = GdiPlus.GetNativeFont(block.Font); + IntPtr native_string_format = GdiPlus.GetNativeStringFormat(format); + + int height = 0; + + // It seems that the mere presence of \n and \r characters + // is enough for Mono to botch the layout (even if these + // characters are not processed.) We'll need to find a + // different way to perform layout on Mono, probably + // through Pango. + // Todo: This workaround allocates memory. + //if (Configuration.RunningOnMono) + { + string[] lines = block.Text.Replace("\r", String.Empty).Split('\n'); + foreach (string s in lines) + { + extents.AddRange(MeasureGlyphExtents( + s, height, 0, s.Length, block.LayoutRectangle, + native_graphics, native_font, native_string_format)); + height += block.Font.Height; + } + } + + extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, extents[extents.Count - 1].Right, extents[extents.Count - 1].Bottom); + } + + #endregion + + #region MeasureGlyphExtents + + // Gets the bounds of each character in a line of text. + // The line is processed in blocks of 32 characters (GdiPlus.MaxMeasurableCharacterRanges). + IEnumerable MeasureGlyphExtents(string text, int height, int line_start, int line_length, + RectangleF layoutRect, IntPtr native_graphics, IntPtr native_font, IntPtr native_string_format) + { + RectangleF rect = new RectangleF(); + int line_end = line_start + line_length; + while (line_start < line_end) + { + //if (text[line_start] == '\n' || text[line_start] == '\r') + //{ + // line_start++; + // continue; + //} + + int num_characters = (line_end - line_start) > GdiPlus.MaxMeasurableCharacterRanges ? + GdiPlus.MaxMeasurableCharacterRanges : + line_end - line_start; + int status = 0; + + for (int i = 0; i < num_characters; i++) + { + characterRanges[i] = new CharacterRange(line_start + i, 1); + + IntPtr region; + status = GdiPlus.CreateRegion(out region); + regions[i] = region; + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + } + + status = GdiPlus.SetStringFormatMeasurableCharacterRanges(native_string_format, num_characters, characterRanges); + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + + status = GdiPlus.MeasureCharacterRanges(native_graphics, text, text.Length, + native_font, ref layoutRect, native_string_format, num_characters, regions); + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + + for (int i = 0; i < num_characters; i++) + { + GdiPlus.GetRegionBounds(regions[i], native_graphics, ref rect); + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + GdiPlus.DeleteRegion(regions[i]); + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + + rect.Y += height; + + yield return rect; + } + + line_start += num_characters; + } + } + + #endregion + + #region FindEdges + + Rectangle FindEdges(Bitmap bmp) + { + return Rectangle.FromLTRB( + FindLeftEdge(bmp), + FindTopEdge(bmp), + FindRightEdge(bmp), + FindBottomEdge(bmp)); + } + + #endregion + + #region Find[Left|Right|Top|Bottom]Edge + + // Iterates through the bmp, and returns the first row or line that contains a non-transparent pixels. + + int FindLeftEdge(Bitmap bmp) + { + for (int x = 0; x < bmp.Width; x++) + for (int y = 0; y < bmp.Height; y++) + if (bmp.GetPixel(x, y).A != 0) + return x; + + return bmp.Width; + } + + int FindRightEdge(Bitmap bmp) + { + for (int x = bmp.Width - 1; x >= 0; x--) + for (int y = 0; y < bmp.Height; y++) + if (bmp.GetPixel(x, y).A != 0) + return x + 1; + + return 0; + } + + int FindTopEdge(Bitmap bmp) + { + // Don't trim the top edge, because the layout engine expects it to be 0. + return 0; + } + + int FindBottomEdge(Bitmap bmp) + { + for (int y = bmp.Height - 1; y >= 0; y--) + for (int x = 0; x < bmp.Width; x++) + if (bmp.GetPixel(x, y).A != 0) + return y + 1; + + return 0; + } + + #endregion + + #endregion + } +} From 30f75d4389035e185c6f6d431bb9e596513343ad Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 14:04:24 +0000 Subject: [PATCH 07/53] Added missing license notice. --- Source/Utilities/Graphics/AlphaTexture2D.cs | 27 ++++++ Source/Utilities/Graphics/CachedGlyphInfo.cs | 27 ++++++ .../Graphics/GraphicsResourceException.cs | 27 ++++++ .../Utilities/Graphics/IGraphicsResource.cs | 27 ++++++ .../Graphics/Text/GL1TextOutputProvider.cs | 37 +++++++- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 87 +++++++++++-------- Source/Utilities/Graphics/Text/Glyph.cs | 27 ++++++ Source/Utilities/Graphics/Text/GlyphCache.cs | 27 ++++++ Source/Utilities/Graphics/Text/GlyphPacker.cs | 27 ++++++ Source/Utilities/Graphics/Text/GlyphSheet.cs | 27 ++++++ .../Graphics/Text/IGlyphRasterizer.cs | 29 ++++++- .../Graphics/Text/ITextOutputProvider.cs | 27 ++++++ Source/Utilities/Graphics/Text/TextBlock.cs | 27 ++++++ .../Graphics/Text/TextBlockComparer.cs | 27 ++++++ Source/Utilities/Graphics/Text/TextExtents.cs | 27 ++++++ Source/Utilities/Graphics/TextureRegion2D.cs | 27 ++++++ 16 files changed, 464 insertions(+), 40 deletions(-) diff --git a/Source/Utilities/Graphics/AlphaTexture2D.cs b/Source/Utilities/Graphics/AlphaTexture2D.cs index d4db7676..ac3686f7 100644 --- a/Source/Utilities/Graphics/AlphaTexture2D.cs +++ b/Source/Utilities/Graphics/AlphaTexture2D.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/CachedGlyphInfo.cs b/Source/Utilities/Graphics/CachedGlyphInfo.cs index e5154f18..037ed7e0 100644 --- a/Source/Utilities/Graphics/CachedGlyphInfo.cs +++ b/Source/Utilities/Graphics/CachedGlyphInfo.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/GraphicsResourceException.cs b/Source/Utilities/Graphics/GraphicsResourceException.cs index 8a7aa297..a1232dbc 100644 --- a/Source/Utilities/Graphics/GraphicsResourceException.cs +++ b/Source/Utilities/Graphics/GraphicsResourceException.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/IGraphicsResource.cs b/Source/Utilities/Graphics/IGraphicsResource.cs index 7d5d4987..0bebdb1c 100644 --- a/Source/Utilities/Graphics/IGraphicsResource.cs +++ b/Source/Utilities/Graphics/IGraphicsResource.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index 78787978..cecc3372 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -1,12 +1,47 @@ +#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; +using OpenTK.Math; + namespace OpenTK.Graphics.Text { class GL1TextOutputProvider : ITextOutputProvider { + #region Fields + + SortedList> vertices = new SortedList>(); + + #endregion + #region Constructors public GL1TextOutputProvider() { } @@ -23,7 +58,7 @@ namespace OpenTK.Graphics.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.BindTexture(TextureTarget.Texture2D, 2); //GL.Begin(BeginMode.Quads); diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index 92b13e6d..cbe58047 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -1,3 +1,30 @@ +#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; @@ -51,20 +78,10 @@ namespace OpenTK.Graphics.Text 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)) { - // Small sizes look blurry without gridfitting, so turn that on. - if (glyph.Font.Size <= 18.0f) - gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; - else - gfx.TextRenderingHint = TextRenderingHint.AntiAlias; + SetTextRenderingOptions(gfx, glyph.Font); - gfx.Clear(Color.Transparent); - gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty); - - Rectangle tight_rect = FindEdges(bmp); - Bitmap tight_glyph = bmp.Clone(tight_rect, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - //new Bitmap(tight_rect.Width, tight_rect.Height); - //return bmp.Clone(FindEdges(bmp), System.Drawing.Imaging.PixelFormat.Format32bppArgb); - return tight_glyph; + gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, load_glyph_string_format); + return bmp.Clone(FindEdges(bmp), System.Drawing.Imaging.PixelFormat.Format32bppArgb); } } @@ -72,11 +89,6 @@ namespace OpenTK.Graphics.Text #region MeasureText - //public RectangleF MeasureText(TextBlock block) - //{ - // return MeasureText(block, ref extents); - //} - public TextExtents MeasureText(TextBlock block) { // First, check if we have cached this text block. Do not use block_cache.TryGetValue, to avoid thrashing @@ -94,22 +106,24 @@ namespace OpenTK.Graphics.Text #endregion - #region MeasureGlyph - - public RectangleF MeasureGlyph(Glyph glyph) - { - using (Bitmap bmp = Rasterize(glyph)) - { - return FindEdges(bmp); - } - } - - #endregion - #endregion #region Private Members + #region SetRenderingOptions + + // Modify rendering settings (antialiasing, grid fitting) to improve appearance. + void SetTextRenderingOptions(System.Drawing.Graphics gfx, Font font) + { + // Small sizes look blurry without gridfitting, so turn that on. + if (font.Size <= 18.0f) + gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + else + gfx.TextRenderingHint = TextRenderingHint.AntiAlias; + } + + #endregion + #region MeasureTextExtents void MeasureTextExtents(TextBlock block, ref TextExtents extents) @@ -122,6 +136,8 @@ namespace OpenTK.Graphics.Text PointF origin = PointF.Empty; SizeF size = SizeF.Empty; + SetTextRenderingOptions(graphics, block.Font); + IntPtr native_graphics = GdiPlus.GetNativeGraphics(graphics); IntPtr native_font = GdiPlus.GetNativeFont(block.Font); IntPtr native_string_format = GdiPlus.GetNativeStringFormat(format); @@ -140,7 +156,8 @@ namespace OpenTK.Graphics.Text foreach (string s in lines) { extents.AddRange(MeasureGlyphExtents( - s, height, 0, s.Length, block.LayoutRectangle, + s, height, 0, s.Length, + block.LayoutRectangle, native_graphics, native_font, native_string_format)); height += block.Font.Height; } @@ -227,12 +244,8 @@ namespace OpenTK.Graphics.Text int FindLeftEdge(Bitmap bmp) { - for (int x = 0; x < bmp.Width; x++) - for (int y = 0; y < bmp.Height; y++) - if (bmp.GetPixel(x, y).A != 0) - return x; - - return bmp.Width; + // Don't trim the left edge, because the layout engine expects it to be 0. + return 0; } int FindRightEdge(Bitmap bmp) diff --git a/Source/Utilities/Graphics/Text/Glyph.cs b/Source/Utilities/Graphics/Text/Glyph.cs index aea2403b..f60ce3e6 100644 --- a/Source/Utilities/Graphics/Text/Glyph.cs +++ b/Source/Utilities/Graphics/Text/Glyph.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/Text/GlyphCache.cs b/Source/Utilities/Graphics/Text/GlyphCache.cs index e862df9e..514f43ee 100644 --- a/Source/Utilities/Graphics/Text/GlyphCache.cs +++ b/Source/Utilities/Graphics/Text/GlyphCache.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/Text/GlyphPacker.cs b/Source/Utilities/Graphics/Text/GlyphPacker.cs index 90e9c4ce..dd3ccb80 100644 --- a/Source/Utilities/Graphics/Text/GlyphPacker.cs +++ b/Source/Utilities/Graphics/Text/GlyphPacker.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/Text/GlyphSheet.cs b/Source/Utilities/Graphics/Text/GlyphSheet.cs index 1a709eb2..b2fbbc5d 100644 --- a/Source/Utilities/Graphics/Text/GlyphSheet.cs +++ b/Source/Utilities/Graphics/Text/GlyphSheet.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs index f8b2d2e8..dc568191 100644 --- a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs +++ b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs @@ -1,3 +1,30 @@ +#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; @@ -10,8 +37,6 @@ namespace OpenTK.Graphics.Text interface IGlyphRasterizer { Bitmap Rasterize(Glyph glyph); - //void Rasterize(Glyph glyph, ref Bitmap bmp); TextExtents MeasureText(TextBlock block); - RectangleF MeasureGlyph(Glyph glyph); } } diff --git a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs index 4090d0e8..095a5646 100644 --- a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/Text/TextBlock.cs b/Source/Utilities/Graphics/Text/TextBlock.cs index ed235cec..570827b5 100644 --- a/Source/Utilities/Graphics/Text/TextBlock.cs +++ b/Source/Utilities/Graphics/Text/TextBlock.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/Text/TextBlockComparer.cs b/Source/Utilities/Graphics/Text/TextBlockComparer.cs index 524ba106..681524b2 100644 --- a/Source/Utilities/Graphics/Text/TextBlockComparer.cs +++ b/Source/Utilities/Graphics/Text/TextBlockComparer.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/Text/TextExtents.cs b/Source/Utilities/Graphics/Text/TextExtents.cs index 98ae31bc..3f646b4b 100644 --- a/Source/Utilities/Graphics/Text/TextExtents.cs +++ b/Source/Utilities/Graphics/Text/TextExtents.cs @@ -1,3 +1,30 @@ +#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; diff --git a/Source/Utilities/Graphics/TextureRegion2D.cs b/Source/Utilities/Graphics/TextureRegion2D.cs index d44969f4..9d02aa05 100644 --- a/Source/Utilities/Graphics/TextureRegion2D.cs +++ b/Source/Utilities/Graphics/TextureRegion2D.cs @@ -1,3 +1,30 @@ +#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; From 71addb49239f01a1c2849c8baed927fe46483117 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 16:10:18 +0000 Subject: [PATCH 08/53] Derive AlphaTexture2D from Texture2D. --- Source/Utilities/Graphics/AlphaTexture2D.cs | 171 +------------ Source/Utilities/Graphics/Texture2D.cs | 259 ++++++++++++++++++++ 2 files changed, 265 insertions(+), 165 deletions(-) create mode 100644 Source/Utilities/Graphics/Texture2D.cs diff --git a/Source/Utilities/Graphics/AlphaTexture2D.cs b/Source/Utilities/Graphics/AlphaTexture2D.cs index ac3686f7..637e4ec5 100644 --- a/Source/Utilities/Graphics/AlphaTexture2D.cs +++ b/Source/Utilities/Graphics/AlphaTexture2D.cs @@ -36,15 +36,10 @@ namespace OpenTK.Graphics /// /// Encapsulates an OpenGL texture. /// - class AlphaTexture2D : IGraphicsResource + class AlphaTexture2D : Texture2D { #region Fields - GraphicsContext context; - int id; - int width, height; - bool disposed; - #endregion #region Constructors @@ -53,174 +48,20 @@ namespace OpenTK.Graphics /// Constructs a new Texture. /// public AlphaTexture2D(int width, int height) - { - Width = width; - Height = height; - } - - #endregion - - #region IGraphicsResource Members - - GraphicsContext IGraphicsResource.Context { get { return context; } } - - int IGraphicsResource.Id - { - get - { - if (id == 0) - { - GraphicsContext.Assert(); - context = GraphicsContext.CurrentContext; - - id = GL.GenTexture(); - if (id == 0) - throw new GraphicsResourceException(String.Format("Texture creation failed, (Error: {0})", GL.GetError())); - - // Ensure the texture is allocated. - GL.BindTexture(TextureTarget.Texture2D, id); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); - if (GL.SupportsExtension("Version12")) - { - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge); - } - else - { - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Clamp); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Clamp); - } - - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Alpha, Width, Height, 0, - OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); - } - - return id; - } - } + : base(width, height) + { } #endregion #region Public Members - #region public int Width - - /// Gets the width of the texture. - public int Width { get { return width; } private set { width = value; } } - #endregion - #region public int Height + #region Protected Members - /// Gets the height of the texture. - public int Height { get { return height; } private set { height = value; } } - - #endregion - - #region WriteRegion - - public void WriteRegion(Rectangle source, Rectangle target, int mipLevel, Bitmap bitmap) + protected override PixelInternalFormat InternalFormat { - if (bitmap == null) - throw new ArgumentNullException("data"); - - GraphicsUnit unit = GraphicsUnit.Pixel; - - if (!bitmap.GetBounds(ref unit).Contains(source)) - throw new InvalidOperationException("The source Rectangle is larger than the Bitmap."); - - if (mipLevel < 0) - throw new ArgumentOutOfRangeException("mipLevel"); - - Bind(); - - BitmapData data = bitmap.LockBits(source, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - - GL.PushClientAttrib(ClientAttribMask.ClientPixelStoreBit); - try - { - GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); - GL.PixelStore(PixelStoreParameter.UnpackRowLength, bitmap.Width); - GL.TexSubImage2D(TextureTarget.Texture2D, mipLevel, - target.Left, target.Top, - target.Width, target.Height, - OpenTK.Graphics.PixelFormat.Rgba, - PixelType.UnsignedByte, data.Scan0); - } - finally - { - GL.PopClientAttrib(); - } - - bitmap.UnlockBits(data); - } - - public void WriteRegion(TextureRegion2D region, int mipLevel) - { - if (mipLevel < 0) - throw new ArgumentOutOfRangeException("miplevel"); - - GL.TexSubImage2D(TextureTarget.Texture2D, mipLevel, - region.Rectangle.X, region.Rectangle.Y, - region.Rectangle.Width, region.Rectangle.Height, - PixelFormat.Bgra, PixelType.UnsignedByte, region); - } - - #endregion - - #region ReadRegion - - public TextureRegion2D ReadRegion(Rectangle rect, int mipLevel) - { - if (mipLevel < 0) - throw new ArgumentOutOfRangeException("miplevel"); - - TextureRegion2D region = new TextureRegion2D(rect); - - GL.GetTexImage(TextureTarget.Texture2D, mipLevel, PixelFormat.Bgra, PixelType.UnsignedByte, region.Data); - - return region; - } - - #endregion - - #region Bind - - public void Bind() - { - GL.BindTexture(TextureTarget.Texture2D, (this as IGraphicsResource).Id); - } - - #endregion - - #endregion - - #region IDisposable Members - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - void Dispose(bool manual) - { - if (!disposed) - { - if (manual) - { - GL.DeleteTexture(id); - } - disposed = true; - } - } - - ~AlphaTexture2D() - { - GraphicsContext context = (this as IGraphicsResource).Context; - if (context != null) - (context as IGraphicsContextInternal).RegisterForDisposal(this); + get { return PixelInternalFormat.Alpha; } } #endregion diff --git a/Source/Utilities/Graphics/Texture2D.cs b/Source/Utilities/Graphics/Texture2D.cs new file mode 100644 index 00000000..6ab7cbc1 --- /dev/null +++ b/Source/Utilities/Graphics/Texture2D.cs @@ -0,0 +1,259 @@ +#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; +using System.Drawing.Imaging; + +namespace OpenTK.Graphics +{ + abstract class Texture2D : IGraphicsResource + { + #region Fields + + GraphicsContext context; + int id; + int width, height; + bool disposed; + + TextureMagFilter mag_filter = TextureMagFilter.Linear; + TextureMinFilter min_filter = TextureMinFilter.Linear; + + #endregion + + #region Constructors + + public Texture2D(int width, int height) + { + if (width <= 0) + throw new ArgumentOutOfRangeException("width"); + + if (height <= 0) + throw new ArgumentOutOfRangeException("height"); + + Width = width; + Height = height; + } + + #endregion + + #region Public Members + + #region public int Width + + /// Gets the width of the texture. + public int Width { get { return width; } private set { width = value; } } + + #endregion + + #region public int Height + + /// Gets the height of the texture. + public int Height { get { return height; } private set { height = value; } } + + #endregion + + #region MagnificationFilter + + public TextureMagFilter MagnificationFilter + { + get { return mag_filter; } + set { mag_filter = value; } + } + + #endregion + + #region MinificationFilter + + public TextureMinFilter MinificationFilter + { + get { return min_filter; } + set { min_filter = value; } + } + + #endregion + + #region Bind + + public void Bind() + { + GL.BindTexture(TextureTarget.Texture2D, (this as IGraphicsResource).Id); + } + + #endregion + + #region WriteRegion + + public void WriteRegion(Rectangle source, Rectangle target, int mipLevel, Bitmap bitmap) + { + if (bitmap == null) + throw new ArgumentNullException("data"); + + GraphicsUnit unit = GraphicsUnit.Pixel; + + if (!bitmap.GetBounds(ref unit).Contains(source)) + throw new InvalidOperationException("The source Rectangle is larger than the Bitmap."); + + if (mipLevel < 0) + throw new ArgumentOutOfRangeException("mipLevel"); + + Bind(); + + BitmapData data = null; + + GL.PushClientAttrib(ClientAttribMask.ClientPixelStoreBit); + try + { + data = bitmap.LockBits(source, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); + GL.PixelStore(PixelStoreParameter.UnpackRowLength, bitmap.Width); + GL.TexSubImage2D(TextureTarget.Texture2D, mipLevel, + target.Left, target.Top, + target.Width, target.Height, + OpenTK.Graphics.PixelFormat.Rgba, + PixelType.UnsignedByte, data.Scan0); + } + finally + { + GL.PopClientAttrib(); + if (data != null) + bitmap.UnlockBits(data); + } + } + + #endregion + + #region ReadRegion + + public TextureRegion2D ReadRegion(Rectangle rect, int mipLevel) + { + if (mipLevel < 0) + throw new ArgumentOutOfRangeException("miplevel"); + + TextureRegion2D region = new TextureRegion2D(rect); + + GL.GetTexImage(TextureTarget.Texture2D, mipLevel, PixelFormat.Bgra, PixelType.UnsignedByte, region.Data); + + return region; + } + + #endregion + + #endregion + + #region Protected Members + + #region InternalFormat + + protected abstract PixelInternalFormat InternalFormat { get; } + + #endregion + + #endregion + + #region IGraphicsResource Members + + #region IGraphicsResource.Context + + GraphicsContext IGraphicsResource.Context { get { return context; } } + + #endregion + + #region IGraphicsResource.Id + + int IGraphicsResource.Id + { + get + { + if (id == 0) + { + GraphicsContext.Assert(); + context = GraphicsContext.CurrentContext; + + id = GL.GenTexture(); + if (id == 0) + throw new GraphicsResourceException(String.Format("Texture creation failed, (Error: {0})", GL.GetError())); + + // Ensure the texture is allocated. + GL.BindTexture(TextureTarget.Texture2D, id); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); + if (GL.SupportsExtension("Version12")) + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge); + } + else + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Clamp); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Clamp); + } + + GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat, Width, Height, 0, + OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); + } + + return id; + } + } + + #endregion + + #endregion + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool manual) + { + if (!disposed) + { + if (manual) + { + GL.DeleteTexture(id); + } + disposed = true; + } + } + + ~Texture2D() + { + GraphicsContext context = (this as IGraphicsResource).Context; + if (context != null) + (context as IGraphicsContextInternal).RegisterForDisposal(this); + } + + #endregion + } +} From 8e7348d085443aa33f67b1dca3ac26e959c0391f Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 16:11:31 +0000 Subject: [PATCH 09/53] Add missing Measure methods. --- Source/Utilities/Fonts/TextPrinter.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Source/Utilities/Fonts/TextPrinter.cs b/Source/Utilities/Fonts/TextPrinter.cs index 54613f94..e1bc9f93 100644 --- a/Source/Utilities/Fonts/TextPrinter.cs +++ b/Source/Utilities/Fonts/TextPrinter.cs @@ -436,6 +436,25 @@ namespace OpenTK.Graphics #endregion + #region Measure + + public TextExtents Measure(string text, Font font) + { + return Measure(text, font, 0, RectangleF.Empty); + } + + public TextExtents Measure(string text, Font font, TextPrinterOptions options) + { + return Measure(text, font, options, RectangleF.Empty); + } + + public TextExtents Measure(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle) + { + return glyph_rasterizer.MeasureText(new TextBlock(text, font, options, layoutRectangle)); + } + + #endregion + #endregion #region Private Members From d840251dbd6e9d9d5955ffec906725bfef9d8375 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 16:43:21 +0000 Subject: [PATCH 10/53] Use base Texture2D instead of AlphaTexture2D. --- Source/Utilities/Graphics/CachedGlyphInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Utilities/Graphics/CachedGlyphInfo.cs b/Source/Utilities/Graphics/CachedGlyphInfo.cs index 037ed7e0..d5ff0f05 100644 --- a/Source/Utilities/Graphics/CachedGlyphInfo.cs +++ b/Source/Utilities/Graphics/CachedGlyphInfo.cs @@ -34,7 +34,7 @@ namespace OpenTK.Graphics { struct CachedGlyphInfo { - public readonly AlphaTexture2D Texture; + public readonly Texture2D Texture; public readonly RectangleF RectangleNormalized; public Rectangle Rectangle { @@ -49,7 +49,7 @@ namespace OpenTK.Graphics } // Rect denotes the absolute position of the glyph in the texture [0, Texture.Width], [0, Texture.Height]. - public CachedGlyphInfo(AlphaTexture2D texture, Rectangle rect) + public CachedGlyphInfo(Texture2D texture, Rectangle rect) { Texture = texture; RectangleNormalized = new RectangleF( From 8249b75f42f03f008eeb43a9b58d82123cecb3f2 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 16:44:52 +0000 Subject: [PATCH 11/53] Added IEquatable interface to allow use as key in dictionaries. --- Source/Utilities/Graphics/Texture2D.cs | 28 +++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Source/Utilities/Graphics/Texture2D.cs b/Source/Utilities/Graphics/Texture2D.cs index 6ab7cbc1..6e487425 100644 --- a/Source/Utilities/Graphics/Texture2D.cs +++ b/Source/Utilities/Graphics/Texture2D.cs @@ -33,7 +33,7 @@ using System.Drawing.Imaging; namespace OpenTK.Graphics { - abstract class Texture2D : IGraphicsResource + abstract class Texture2D : IGraphicsResource, IEquatable { #region Fields @@ -165,6 +165,23 @@ namespace OpenTK.Graphics #endregion + #region Equals + + public override bool Equals(object obj) + { + if (obj is Texture2D) + return this.Equals((Texture2D)obj); + + return false; + } + + #endregion + + //public override int GetHashCode() + //{ + // return (this as IGraphicsResource).Id; + //} + #endregion #region Protected Members @@ -227,6 +244,15 @@ namespace OpenTK.Graphics #endregion + #region IEquatable Members + + public bool Equals(Texture2D other) + { + return (this as IGraphicsResource).Id == (other as IGraphicsResource).Id; + } + + #endregion + #region IDisposable Members public void Dispose() From 15eaba60a910c9532b6d7d2bd13e3bbb1efb8787 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 16:45:24 +0000 Subject: [PATCH 12/53] Implement support for multiple texture sheets. --- .../Graphics/Text/GL1TextOutputProvider.cs | 74 ++++++++++++++----- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index cecc3372..6e507d42 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -38,13 +38,18 @@ namespace OpenTK.Graphics.Text { #region Fields - SortedList> vertices = new SortedList>(); + // Triangle lists, sorted by texture. + Dictionary> active_lists = new Dictionary>(); + Queue> inactive_lists = new Queue>(); #endregion #region Constructors - public GL1TextOutputProvider() { } + public GL1TextOutputProvider() + { + inactive_lists.Enqueue(new List()); + } #endregion @@ -75,8 +80,7 @@ namespace OpenTK.Graphics.Text //GL.Translate(0, 256, 0); - GL.Begin(BeginMode.Triangles); - + // Build layout int current = 0; foreach (char c in block.Text) { @@ -90,26 +94,58 @@ namespace OpenTK.Graphics.Text CachedGlyphInfo info = cache[c, block.Font]; RectangleF position = extents[current++]; - + // Use the real glyph width instead of the measured one + // (we want to achieve pixel perfect output). position.Size = info.Rectangle.Size; - // Interleaved array: Vertex, TexCoord, Vertex, ... - GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Top); - GL.Vertex2(position.Left, position.Top); - GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom); - GL.Vertex2(position.Left, position.Bottom); - GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom); - GL.Vertex2(position.Right, position.Bottom); + if (!active_lists.ContainsKey(info.Texture)) + if (inactive_lists.Count > 0) + active_lists.Add(info.Texture, inactive_lists.Dequeue()); + else + active_lists.Add(info.Texture, new List()); + { + // Interleaved array: Vertex, TexCoord, Vertex, ... + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); + active_lists[info.Texture].Add(new Vector2(position.Left, position.Top)); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom)); + active_lists[info.Texture].Add(new Vector2(position.Left, position.Bottom)); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); + active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom)); - GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom); - GL.Vertex2(position.Right, position.Bottom); - GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Top); - GL.Vertex2(position.Right, position.Top); - GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Top); - GL.Vertex2(position.Left, position.Top); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); + active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom)); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Top)); + active_lists[info.Texture].Add(new Vector2(position.Right, position.Top)); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); + active_lists[info.Texture].Add(new Vector2(position.Left, position.Top)); + } } - GL.End(); + // Render + foreach (Texture2D key in active_lists.Keys) + { + List list = active_lists[key]; + + key.Bind(); + GL.Begin(BeginMode.Triangles); + + for (int i = 0; i < list.Count; i += 2) + { + GL.TexCoord2(list[i]); + GL.Vertex2(list[i + 1]); + } + + GL.End(); + } + + // Clean layout + foreach (List list in active_lists.Values) + { + list.Clear(); + inactive_lists.Enqueue(list); + } + + active_lists.Clear(); } #endregion From fa12673450fb3ca1cdc22d9128cc71f741cb2487 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 17:16:57 +0000 Subject: [PATCH 13/53] Updated ITextPrinter interface for the new implementation. --- Source/Utilities/Fonts/ITextPrinter.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/Utilities/Fonts/ITextPrinter.cs b/Source/Utilities/Fonts/ITextPrinter.cs index 00193ca7..c39b46bf 100644 --- a/Source/Utilities/Fonts/ITextPrinter.cs +++ b/Source/Utilities/Fonts/ITextPrinter.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Text; using System.Drawing; +using OpenTK.Graphics.Text; namespace OpenTK.Graphics { @@ -16,13 +17,13 @@ namespace OpenTK.Graphics /// public interface ITextPrinter { - void Prepare(string text, TextureFont font, out TextHandle handle); - void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp); - void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment); - void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment, bool rightToLeft); - void Draw(TextHandle handle); - void Draw(string text, TextureFont font); void Begin(); void End(); + void Print(string text, Font font); + void Print(string text, Font font, TextPrinterOptions options); + void Print(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle); + TextExtents Measure(string text, Font font); + TextExtents Measure(string text, Font font, TextPrinterOptions options); + TextExtents Measure(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle); } } From 732a602578ce45383c4ebfbc07ce9ae87657efe7 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 17:24:40 +0000 Subject: [PATCH 14/53] Added TextPrinterOptions.Default. --- Source/Utilities/Fonts/TextPrinterOptions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Utilities/Fonts/TextPrinterOptions.cs b/Source/Utilities/Fonts/TextPrinterOptions.cs index 55fb7dd0..15bd1739 100644 --- a/Source/Utilities/Fonts/TextPrinterOptions.cs +++ b/Source/Utilities/Fonts/TextPrinterOptions.cs @@ -7,6 +7,7 @@ namespace OpenTK.Graphics [Flags] public enum TextPrinterOptions { + Default = 0, NoCache = 1, RightToLeft = 2, Vertical = 4, From 5d1eda9289e8fb00bd2d8d513cf38ab42411af13 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 17:25:10 +0000 Subject: [PATCH 15/53] Implemented GetHashCode and ToString. --- Source/Utilities/Graphics/Texture2D.cs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Source/Utilities/Graphics/Texture2D.cs b/Source/Utilities/Graphics/Texture2D.cs index 6e487425..9be42a3d 100644 --- a/Source/Utilities/Graphics/Texture2D.cs +++ b/Source/Utilities/Graphics/Texture2D.cs @@ -177,10 +177,27 @@ namespace OpenTK.Graphics #endregion - //public override int GetHashCode() - //{ - // return (this as IGraphicsResource).Id; - //} + #region public override int GetHashCode() + + public override int GetHashCode() + { + return (this as IGraphicsResource).Id; + } + + #endregion + + #region public overrid string ToString() + + public override string ToString() + { + return String.Format("Texture2D #{0} ({1}x{2}, {3})", + (this as IGraphicsResource).Id.ToString(), + Width.ToString(), + Height.ToString(), + InternalFormat.ToString()); + } + + #endregion #endregion From e1beaf374433c87ab8813ce801f67ea51deff0cd Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 17:25:51 +0000 Subject: [PATCH 16/53] Updated examples to use the new TextPrinter. --- Source/Examples/OpenGL/FrameBufferObject.cs | 593 ++++++++++---------- Source/Examples/OpenGL/JuliaSetFractal.cs | 4 +- Source/Examples/Tests/GameWindowStates.cs | 10 +- Source/Examples/Tutorial/Fonts.cs | 88 ++- Source/Examples/Tutorial/Text.cs | 31 +- 5 files changed, 361 insertions(+), 365 deletions(-) diff --git a/Source/Examples/OpenGL/FrameBufferObject.cs b/Source/Examples/OpenGL/FrameBufferObject.cs index 811905f5..b87e5a7b 100644 --- a/Source/Examples/OpenGL/FrameBufferObject.cs +++ b/Source/Examples/OpenGL/FrameBufferObject.cs @@ -1,298 +1,299 @@ -#region --- License --- -/* Licensed under the MIT/X11 license. - * Copyright (c) 2006-2008 the OpenTK Team. - * This notice may not be removed from any source distribution. - * See license.txt for licensing details. - */ -#endregion - -using System; -using System.Diagnostics; - -using OpenTK; -using OpenTK.Input; -using OpenTK.Math; -using OpenTK.Graphics; -using OpenTK.Graphics.OpenGL; - -namespace Examples.Tutorial -{ - [Example("Simple FrameBuffer Object.", ExampleCategory.OpenGL)] - public class SimpleFBO : GameWindow - { - public SimpleFBO() - : base(800, 600) - { - } - - TextureFont sans = new TextureFont(new System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, 14.0f)); - ITextPrinter text = new TextPrinter(); - - uint ColorTexture; - uint DepthTexture; - uint FBOHandle; - - const int TextureSize = 512; - - #region Randoms - - Random rnd = new Random(); - public const float scale = 3f; - - /// Returns a random Float in the range [-0.5*scale..+0.5*scale] - public float GetRandom() - { - return (float)(rnd.NextDouble() - 0.5) * scale; - } - - /// Returns a random Float in the range [0..1] - public float GetRandom0to1() - { - return (float)rnd.NextDouble(); - } - - #endregion Randoms - - public override void OnLoad(EventArgs e) - { - GL.Enable(EnableCap.DepthTest); - GL.ClearDepth(1.0f); - GL.DepthFunc(DepthFunction.Lequal); - - GL.Disable(EnableCap.CullFace); - GL.PolygonMode(MaterialFace.Back, PolygonMode.Line); - - // Create Color Tex - GL.GenTextures(1, out ColorTexture); - GL.BindTexture(TextureTarget.Texture2D, ColorTexture); - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, TextureSize, TextureSize, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder); - // GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D ); - - // Create Depth Tex - GL.GenTextures(1, out DepthTexture); - GL.BindTexture(TextureTarget.Texture2D, DepthTexture); - GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormat)All.DepthComponent32, TextureSize, TextureSize, 0, PixelFormat.DepthComponent, PixelType.UnsignedInt, IntPtr.Zero); - // things go horribly wrong if DepthComponent's Bitcount does not match the main Framebuffer's Depth - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder); - // GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D ); - - // Create a FBO and attach the textures - GL.Ext.GenFramebuffers(1, out FBOHandle); - GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, FBOHandle); - GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, ColorTexture, 0); - GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.DepthAttachmentExt, TextureTarget.Texture2D, DepthTexture, 0); - - #region Test for Error - - switch (GL.Ext.CheckFramebufferStatus(FramebufferTarget.FramebufferExt)) - { - case FramebufferErrorCode.FramebufferCompleteExt: - { - Console.WriteLine("FBO: The framebuffer is complete and valid for rendering."); - break; - } - case FramebufferErrorCode.FramebufferIncompleteAttachmentExt: - { - Console.WriteLine("FBO: One or more attachment points are not framebuffer attachment complete. This could mean there’s no texture attached or the format isn’t renderable. For color textures this means the base format must be RGB or RGBA and for depth textures it must be a DEPTH_COMPONENT format. Other causes of this error are that the width or height is zero or the z-offset is out of range in case of render to volume."); - break; - } - case FramebufferErrorCode.FramebufferIncompleteMissingAttachmentExt: - { - Console.WriteLine("FBO: There are no attachments."); - break; - } - /* case FramebufferErrorCode.GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: - { - Console.WriteLine("FBO: An object has been attached to more than one attachment point."); - break; - }*/ - case FramebufferErrorCode.FramebufferIncompleteDimensionsExt: - { - Console.WriteLine("FBO: Attachments are of different size. All attachments must have the same width and height."); - break; - } - case FramebufferErrorCode.FramebufferIncompleteFormatsExt: - { - Console.WriteLine("FBO: The color attachments have different format. All color attachments must have the same format."); - break; - } - case FramebufferErrorCode.FramebufferIncompleteDrawBufferExt: - { - Console.WriteLine("FBO: An attachment point referenced by GL.DrawBuffers() doesn’t have an attachment."); - break; - } - case FramebufferErrorCode.FramebufferIncompleteReadBufferExt: - { - Console.WriteLine("FBO: The attachment point referenced by GL.ReadBuffers() doesn’t have an attachment."); - break; - } - case FramebufferErrorCode.FramebufferUnsupportedExt: - { - Console.WriteLine("FBO: This particular FBO configuration is not supported by the implementation."); - break; - } - default: - { - Console.WriteLine("FBO: Status unknown. (yes, this is really bad.)"); - break; - } - } - - // using FBO might have changed states, e.g. the FBO might not support stereoscopic views or double buffering - int[] queryinfo = new int[6]; - GL.GetInteger(GetPName.MaxColorAttachmentsExt, out queryinfo[0]); - GL.GetInteger(GetPName.AuxBuffers, out queryinfo[1]); - GL.GetInteger(GetPName.MaxDrawBuffers, out queryinfo[2]); - GL.GetInteger(GetPName.Stereo, out queryinfo[3]); - GL.GetInteger(GetPName.Samples, out queryinfo[4]); - GL.GetInteger(GetPName.Doublebuffer, out queryinfo[5]); - Console.WriteLine("max. ColorBuffers: " + queryinfo[0] + " max. AuxBuffers: " + queryinfo[1] + " max. DrawBuffers: " + queryinfo[2] + - "\nStereo: " + queryinfo[3] + " Samples: " + queryinfo[4] + " DoubleBuffer: " + queryinfo[5]); - - Console.WriteLine("Last GL Error: " + GL.GetError()); - - #endregion Test for Error - - GL.PushAttrib(AttribMask.ViewportBit); - { - GL.Viewport(0, 0, TextureSize, TextureSize); - - // clear the screen in red, to make it very obvious what the clear affected. only the FBO, not the real framebuffer - GL.ClearColor(1f, 0f, 0f, 0f); - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - - // smack 50 random triangles into the FBO's textures - GL.Begin(BeginMode.Triangles); - { - for (int i = 0; i < 50; i++) - { - GL.Color3(GetRandom0to1(), GetRandom0to1(), GetRandom0to1()); - GL.Vertex3(GetRandom(), GetRandom(), GetRandom()); - GL.Color3(GetRandom0to1(), GetRandom0to1(), GetRandom0to1()); - GL.Vertex3(GetRandom(), GetRandom(), GetRandom()); - GL.Color3(GetRandom0to1(), GetRandom0to1(), GetRandom0to1()); - GL.Vertex3(GetRandom(), GetRandom(), GetRandom()); - } - } - GL.End(); - } - GL.PopAttrib(); - GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0); // disable rendering into the FBO - - GL.ClearColor(.1f, .2f, .3f, 0f); - GL.Color3(1f, 1f, 1f); - - GL.Enable(EnableCap.Texture2D); // enable Texture Mapping - GL.BindTexture(TextureTarget.Texture2D, 0); // bind default texture - } - - public override void OnUnload(EventArgs e) - { - // Clean up what we allocated before exiting - GL.DeleteTextures(1, ref ColorTexture); - GL.DeleteTextures(1, ref DepthTexture); - GL.Ext.DeleteFramebuffers(1, ref FBOHandle); - - base.OnUnload(e); - } - - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) - { - GL.Viewport(0, 0, Width, Height); - GL.MatrixMode(MatrixMode.Projection); - GL.LoadIdentity(); - Glu.Perspective(60.0, Width / (double)Height, 1.0, 5.0); - - GL.MatrixMode(MatrixMode.Modelview); - GL.LoadIdentity(); - Glu.LookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); - - base.OnResize(e); - } - - public override void OnUpdateFrame(UpdateFrameEventArgs e) - { - base.OnUpdateFrame(e); - - if (Keyboard[Key.Space]) - { - ErrorCode err = GL.GetError(); - Console.WriteLine(err + " " + Glu.ErrorString((GluErrorCode)err)); - } - - if (Keyboard[Key.Escape]) - this.Exit(); - } - - public override void OnRenderFrame(RenderFrameEventArgs e) - { - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - +#region --- License --- +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing details. + */ +#endregion + +using System; +using System.Diagnostics; +using System.Drawing; + +using OpenTK; +using OpenTK.Input; +using OpenTK.Math; +using OpenTK.Graphics; +using OpenTK.Graphics.OpenGL; + +namespace Examples.Tutorial +{ + [Example("Simple FrameBuffer Object.", ExampleCategory.OpenGL)] + public class SimpleFBO : GameWindow + { + public SimpleFBO() + : base(800, 600) + { + } + + Font sans = new Font(System.Drawing.FontFamily.GenericSansSerif, 16.0f); + ITextPrinter text = new TextPrinter(); + + uint ColorTexture; + uint DepthTexture; + uint FBOHandle; + + const int TextureSize = 512; + + #region Randoms + + Random rnd = new Random(); + public const float scale = 3f; + + /// Returns a random Float in the range [-0.5*scale..+0.5*scale] + public float GetRandom() + { + return (float)(rnd.NextDouble() - 0.5) * scale; + } + + /// Returns a random Float in the range [0..1] + public float GetRandom0to1() + { + return (float)rnd.NextDouble(); + } + + #endregion Randoms + + public override void OnLoad(EventArgs e) + { + GL.Enable(EnableCap.DepthTest); + GL.ClearDepth(1.0f); + GL.DepthFunc(DepthFunction.Lequal); + + GL.Disable(EnableCap.CullFace); + GL.PolygonMode(MaterialFace.Back, PolygonMode.Line); + + // Create Color Tex + GL.GenTextures(1, out ColorTexture); + GL.BindTexture(TextureTarget.Texture2D, ColorTexture); + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, TextureSize, TextureSize, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder); + // GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D ); + + // Create Depth Tex + GL.GenTextures(1, out DepthTexture); + GL.BindTexture(TextureTarget.Texture2D, DepthTexture); + GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormat)All.DepthComponent32, TextureSize, TextureSize, 0, PixelFormat.DepthComponent, PixelType.UnsignedInt, IntPtr.Zero); + // things go horribly wrong if DepthComponent's Bitcount does not match the main Framebuffer's Depth + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder); + // GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D ); + + // Create a FBO and attach the textures + GL.Ext.GenFramebuffers(1, out FBOHandle); + GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, FBOHandle); + GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, ColorTexture, 0); + GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.DepthAttachmentExt, TextureTarget.Texture2D, DepthTexture, 0); + + #region Test for Error + + switch (GL.Ext.CheckFramebufferStatus(FramebufferTarget.FramebufferExt)) + { + case FramebufferErrorCode.FramebufferCompleteExt: + { + Console.WriteLine("FBO: The framebuffer is complete and valid for rendering."); + break; + } + case FramebufferErrorCode.FramebufferIncompleteAttachmentExt: + { + Console.WriteLine("FBO: One or more attachment points are not framebuffer attachment complete. This could mean there’s no texture attached or the format isn’t renderable. For color textures this means the base format must be RGB or RGBA and for depth textures it must be a DEPTH_COMPONENT format. Other causes of this error are that the width or height is zero or the z-offset is out of range in case of render to volume."); + break; + } + case FramebufferErrorCode.FramebufferIncompleteMissingAttachmentExt: + { + Console.WriteLine("FBO: There are no attachments."); + break; + } + /* case FramebufferErrorCode.GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: + { + Console.WriteLine("FBO: An object has been attached to more than one attachment point."); + break; + }*/ + case FramebufferErrorCode.FramebufferIncompleteDimensionsExt: + { + Console.WriteLine("FBO: Attachments are of different size. All attachments must have the same width and height."); + break; + } + case FramebufferErrorCode.FramebufferIncompleteFormatsExt: + { + Console.WriteLine("FBO: The color attachments have different format. All color attachments must have the same format."); + break; + } + case FramebufferErrorCode.FramebufferIncompleteDrawBufferExt: + { + Console.WriteLine("FBO: An attachment point referenced by GL.DrawBuffers() doesn’t have an attachment."); + break; + } + case FramebufferErrorCode.FramebufferIncompleteReadBufferExt: + { + Console.WriteLine("FBO: The attachment point referenced by GL.ReadBuffers() doesn’t have an attachment."); + break; + } + case FramebufferErrorCode.FramebufferUnsupportedExt: + { + Console.WriteLine("FBO: This particular FBO configuration is not supported by the implementation."); + break; + } + default: + { + Console.WriteLine("FBO: Status unknown. (yes, this is really bad.)"); + break; + } + } + + // using FBO might have changed states, e.g. the FBO might not support stereoscopic views or double buffering + int[] queryinfo = new int[6]; + GL.GetInteger(GetPName.MaxColorAttachmentsExt, out queryinfo[0]); + GL.GetInteger(GetPName.AuxBuffers, out queryinfo[1]); + GL.GetInteger(GetPName.MaxDrawBuffers, out queryinfo[2]); + GL.GetInteger(GetPName.Stereo, out queryinfo[3]); + GL.GetInteger(GetPName.Samples, out queryinfo[4]); + GL.GetInteger(GetPName.Doublebuffer, out queryinfo[5]); + Console.WriteLine("max. ColorBuffers: " + queryinfo[0] + " max. AuxBuffers: " + queryinfo[1] + " max. DrawBuffers: " + queryinfo[2] + + "\nStereo: " + queryinfo[3] + " Samples: " + queryinfo[4] + " DoubleBuffer: " + queryinfo[5]); + + Console.WriteLine("Last GL Error: " + GL.GetError()); + + #endregion Test for Error + + GL.PushAttrib(AttribMask.ViewportBit); + { + GL.Viewport(0, 0, TextureSize, TextureSize); + + // clear the screen in red, to make it very obvious what the clear affected. only the FBO, not the real framebuffer + GL.ClearColor(1f, 0f, 0f, 0f); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + + // smack 50 random triangles into the FBO's textures + GL.Begin(BeginMode.Triangles); + { + for (int i = 0; i < 50; i++) + { + GL.Color3(GetRandom0to1(), GetRandom0to1(), GetRandom0to1()); + GL.Vertex3(GetRandom(), GetRandom(), GetRandom()); + GL.Color3(GetRandom0to1(), GetRandom0to1(), GetRandom0to1()); + GL.Vertex3(GetRandom(), GetRandom(), GetRandom()); + GL.Color3(GetRandom0to1(), GetRandom0to1(), GetRandom0to1()); + GL.Vertex3(GetRandom(), GetRandom(), GetRandom()); + } + } + GL.End(); + } + GL.PopAttrib(); + GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0); // disable rendering into the FBO + + GL.ClearColor(.1f, .2f, .3f, 0f); + GL.Color3(1f, 1f, 1f); + + GL.Enable(EnableCap.Texture2D); // enable Texture Mapping + GL.BindTexture(TextureTarget.Texture2D, 0); // bind default texture + } + + public override void OnUnload(EventArgs e) + { + // Clean up what we allocated before exiting + GL.DeleteTextures(1, ref ColorTexture); + GL.DeleteTextures(1, ref DepthTexture); + GL.Ext.DeleteFramebuffers(1, ref FBOHandle); + + base.OnUnload(e); + } + + protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + { + GL.Viewport(0, 0, Width, Height); + GL.MatrixMode(MatrixMode.Projection); + GL.LoadIdentity(); + Glu.Perspective(60.0, Width / (double)Height, 1.0, 5.0); + + GL.MatrixMode(MatrixMode.Modelview); + GL.LoadIdentity(); + Glu.LookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); + + base.OnResize(e); + } + + public override void OnUpdateFrame(UpdateFrameEventArgs e) + { + base.OnUpdateFrame(e); + + if (Keyboard[Key.Space]) + { + ErrorCode err = GL.GetError(); + Console.WriteLine(err + " " + Glu.ErrorString((GluErrorCode)err)); + } + + if (Keyboard[Key.Escape]) + this.Exit(); + } + + public override void OnRenderFrame(RenderFrameEventArgs e) + { + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + text.Begin(); - text.Draw((1.0 / e.Time).ToString("F2"), sans); - text.End(); - - GL.PushMatrix(); - { - // Draw the Color Texture - GL.Translate(-1.1f, 0f, 0f); - GL.BindTexture(TextureTarget.Texture2D, ColorTexture); - GL.Begin(BeginMode.Quads); - { - GL.TexCoord2(0f, 1f); - GL.Vertex2(-1.0f, 1.0f); - GL.TexCoord2(0.0f, 0.0f); - GL.Vertex2(-1.0f, -1.0f); - GL.TexCoord2(1.0f, 0.0f); - GL.Vertex2(1.0f, -1.0f); - GL.TexCoord2(1.0f, 1.0f); - GL.Vertex2(1.0f, 1.0f); - } - GL.End(); - - // Draw the Depth Texture - GL.Translate(+2.2f, 0f, 0f); - GL.BindTexture(TextureTarget.Texture2D, DepthTexture); - GL.Begin(BeginMode.Quads); - { - GL.TexCoord2(0f, 1f); - GL.Vertex2(-1.0f, 1.0f); - GL.TexCoord2(0.0f, 0.0f); - GL.Vertex2(-1.0f, -1.0f); - GL.TexCoord2(1.0f, 0.0f); - GL.Vertex2(1.0f, -1.0f); - GL.TexCoord2(1.0f, 1.0f); - GL.Vertex2(1.0f, 1.0f); - } - GL.End(); - } - GL.PopMatrix(); - - this.SwapBuffers(); - } - - #region public static void Main() - - /// - /// Entry point of this example. - /// - [STAThread] - public static void Main() - { - using (SimpleFBO example = new SimpleFBO()) - { - Utilities.SetWindowTitle(example); - example.Run(30.0, 0.0); - } - } - - #endregion - } + text.Print((1.0 / e.Time).ToString("F2"), sans); + text.End(); + + GL.PushMatrix(); + { + // Draw the Color Texture + GL.Translate(-1.1f, 0f, 0f); + GL.BindTexture(TextureTarget.Texture2D, ColorTexture); + GL.Begin(BeginMode.Quads); + { + GL.TexCoord2(0f, 1f); + GL.Vertex2(-1.0f, 1.0f); + GL.TexCoord2(0.0f, 0.0f); + GL.Vertex2(-1.0f, -1.0f); + GL.TexCoord2(1.0f, 0.0f); + GL.Vertex2(1.0f, -1.0f); + GL.TexCoord2(1.0f, 1.0f); + GL.Vertex2(1.0f, 1.0f); + } + GL.End(); + + // Draw the Depth Texture + GL.Translate(+2.2f, 0f, 0f); + GL.BindTexture(TextureTarget.Texture2D, DepthTexture); + GL.Begin(BeginMode.Quads); + { + GL.TexCoord2(0f, 1f); + GL.Vertex2(-1.0f, 1.0f); + GL.TexCoord2(0.0f, 0.0f); + GL.Vertex2(-1.0f, -1.0f); + GL.TexCoord2(1.0f, 0.0f); + GL.Vertex2(1.0f, -1.0f); + GL.TexCoord2(1.0f, 1.0f); + GL.Vertex2(1.0f, 1.0f); + } + GL.End(); + } + GL.PopMatrix(); + + this.SwapBuffers(); + } + + #region public static void Main() + + /// + /// Entry point of this example. + /// + [STAThread] + public static void Main() + { + using (SimpleFBO example = new SimpleFBO()) + { + Utilities.SetWindowTitle(example); + example.Run(30.0, 0.0); + } + } + + #endregion + } } \ No newline at end of file diff --git a/Source/Examples/OpenGL/JuliaSetFractal.cs b/Source/Examples/OpenGL/JuliaSetFractal.cs index 2ea7add4..08442e24 100644 --- a/Source/Examples/OpenGL/JuliaSetFractal.cs +++ b/Source/Examples/OpenGL/JuliaSetFractal.cs @@ -55,7 +55,7 @@ namespace Examples.Tutorial // Text drawing (for fps) TextPrinter printer = new TextPrinter(); - TextureFont font = new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f)); + Font font = new Font(FontFamily.GenericSansSerif, 16.0f); #endregion private Fields @@ -290,7 +290,7 @@ namespace Examples.Tutorial GL.UseProgram(0); printer.Begin(); GL.Color3(Color.PaleGoldenrod); - printer.Draw((1 / e.Time).ToString("F2"), font); + printer.Print((1 / e.Time).ToString("F2"), font, TextPrinterOptions.NoCache); printer.End(); SwapBuffers(); diff --git a/Source/Examples/Tests/GameWindowStates.cs b/Source/Examples/Tests/GameWindowStates.cs index 5d81a28d..4ef3761c 100644 --- a/Source/Examples/Tests/GameWindowStates.cs +++ b/Source/Examples/Tests/GameWindowStates.cs @@ -20,7 +20,7 @@ namespace Examples.Tests [Example("GameWindow states", ExampleCategory.Test)] public class GameWindowStates : GameWindow { - TextureFont font = new TextureFont(new Font(FontFamily.GenericSansSerif, 16.0f)); + Font font = new Font(FontFamily.GenericSansSerif, 16.0f); TextPrinter printer = new TextPrinter(); #region GetNext and GetPrevious methods for enums. @@ -118,12 +118,12 @@ namespace Examples.Tests printer.Begin(); - printer.Draw("Instructions:", font); GL.Translate(0, font.Height, 0); - printer.Draw(String.Format("1 - cycle through window styles (current: {0}).", this.WindowState), font); + printer.Print("Instructions:", font); GL.Translate(0, font.Height, 0); + printer.Print(String.Format("1 - cycle through window styles (current: {0}).", this.WindowState), font); GL.Translate(0, font.Height, 0); - printer.Draw(String.Format("2 - cycle through window borders (current: {0}).", this.WindowBorder), font); + printer.Print(String.Format("2 - cycle through window borders (current: {0}).", this.WindowBorder), font); GL.Translate(0, font.Height, 0); - printer.Draw(String.Format("3 - toggle fullscreen (current: {0}).", + printer.Print(String.Format("3 - toggle fullscreen (current: {0}).", this.WindowState == WindowState.Fullscreen ? "enabled" : "disabled"), font); diff --git a/Source/Examples/Tutorial/Fonts.cs b/Source/Examples/Tutorial/Fonts.cs index 0113dd9c..3973c3fe 100644 --- a/Source/Examples/Tutorial/Fonts.cs +++ b/Source/Examples/Tutorial/Fonts.cs @@ -33,52 +33,50 @@ namespace Examples.Tutorial ITextPrinter printer = new TextPrinter(); const string text = "Hello, world!"; - TextHandle[] handles; // Used to cache the strings we want to print. - // Load some different TextureFont sizes to compare their quality. // You'll never need to load that many fonts in your application, // 3 or 4 should be more than enough. - TextureFont[] fonts = new TextureFont[] + Font[] fonts = new Font[] { - new TextureFont(new Font(FontFamily.GenericSerif, 8.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 10.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 12.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 14.0f)), + new Font(FontFamily.GenericSerif, 8.0f), + new Font(FontFamily.GenericSerif, 10.0f), + new Font(FontFamily.GenericSerif, 12.0f), + new Font(FontFamily.GenericSerif, 14.0f), - new TextureFont(new Font(FontFamily.GenericSerif, 16.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 18.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 20.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 22.0f)), + new Font(FontFamily.GenericSerif, 16.0f), + new Font(FontFamily.GenericSerif, 18.0f), + new Font(FontFamily.GenericSerif, 20.0f), + new Font(FontFamily.GenericSerif, 22.0f), - new TextureFont(new Font(FontFamily.GenericSerif, 24.0f, FontStyle.Bold)), - new TextureFont(new Font(FontFamily.GenericSerif, 26.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 28.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 30.0f)), + new Font(FontFamily.GenericSerif, 24.0f, FontStyle.Bold), + new Font(FontFamily.GenericSerif, 26.0f), + new Font(FontFamily.GenericSerif, 28.0f), + new Font(FontFamily.GenericSerif, 30.0f), - new TextureFont(new Font(FontFamily.GenericSerif, 32.0f, FontStyle.Italic)), - new TextureFont(new Font(FontFamily.GenericSerif, 34.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 36.0f)), - new TextureFont(new Font(FontFamily.GenericSerif, 38.0f)), + new Font(FontFamily.GenericSerif, 32.0f, FontStyle.Italic), + new Font(FontFamily.GenericSerif, 34.0f), + new Font(FontFamily.GenericSerif, 36.0f), + new Font(FontFamily.GenericSerif, 38.0f), - new TextureFont(new Font(FontFamily.GenericSansSerif, 8.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 10.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 12.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f)), + new Font(FontFamily.GenericSansSerif, 8.0f), + new Font(FontFamily.GenericSansSerif, 10.0f), + new Font(FontFamily.GenericSansSerif, 12.0f), + new Font(FontFamily.GenericSansSerif, 14.0f), - new TextureFont(new Font(FontFamily.GenericSansSerif, 16.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 18.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 20.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 22.0f)), + new Font(FontFamily.GenericSansSerif, 16.0f), + new Font(FontFamily.GenericSansSerif, 18.0f), + new Font(FontFamily.GenericSansSerif, 20.0f), + new Font(FontFamily.GenericSansSerif, 22.0f), - new TextureFont(new Font(FontFamily.GenericSansSerif, 24.0f, FontStyle.Bold)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 26.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 28.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 30.0f)), + new Font(FontFamily.GenericSansSerif, 24.0f, FontStyle.Bold), + new Font(FontFamily.GenericSansSerif, 26.0f), + new Font(FontFamily.GenericSansSerif, 28.0f), + new Font(FontFamily.GenericSansSerif, 30.0f), - new TextureFont(new Font(FontFamily.GenericSansSerif, 32.0f, FontStyle.Italic)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 34.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 36.0f)), - new TextureFont(new Font(FontFamily.GenericSansSerif, 38.0f)), + new Font(FontFamily.GenericSansSerif, 32.0f, FontStyle.Italic), + new Font(FontFamily.GenericSansSerif, 34.0f), + new Font(FontFamily.GenericSansSerif, 36.0f), + new Font(FontFamily.GenericSansSerif, 38.0f), }; #endregion @@ -99,10 +97,6 @@ namespace Examples.Tutorial public override void OnLoad(EventArgs e) { GL.ClearColor(Color.SteelBlue); - - handles = new TextHandle[fonts.Length]; - for (int i = handles.Length; --i >= 0; ) - printer.Prepare(text, fonts[i], out handles[i]); } #endregion @@ -117,9 +111,7 @@ namespace Examples.Tutorial /// public override void OnUnload(EventArgs e) { - foreach (TextHandle h in handles) - h.Dispose(); - foreach (TextureFont f in fonts) + foreach (Font f in fonts) f.Dispose(); } @@ -168,21 +160,21 @@ namespace Examples.Tutorial printer.Begin(); // Print using the first font. - for (int i = 0; i < handles.Length / 2; i++) + for (int i = 0; i < fonts.Length / 2; i++) { - printer.Draw(handles[i]); + printer.Print(text, fonts[i]); GL.Translate(0, fonts[i].Height, 0); } // Move to the right, and print using the second font. //float width, height; - //fonts[handles.Length / 2 - 1].MeasureString(text, out width, out height); - RectangleF rect = fonts[handles.Length / 2 - 1].MeasureText(text); + //fonts[handles.Length / 2 - 1].MeasureString(text, out width, out height); + RectangleF rect = printer.Measure(text, fonts[fonts.Length / 2 - 1]).BoundingBox; GL.LoadIdentity(); GL.Translate(rect.Width + 32.0f, 0, 0); - for (int i = handles.Length / 2; i < handles.Length; i++) + for (int i = fonts.Length / 2; i < fonts.Length; i++) { - printer.Draw(handles[i]); + printer.Print(text, fonts[i]); GL.Translate(0, fonts[i].Height, 0); } diff --git a/Source/Examples/Tutorial/Text.cs b/Source/Examples/Tutorial/Text.cs index 0fd3cdd5..fa2dcf72 100644 --- a/Source/Examples/Tutorial/Text.cs +++ b/Source/Examples/Tutorial/Text.cs @@ -23,13 +23,12 @@ namespace Examples.Tutorial [Example("Text", ExampleCategory.Tutorial, 4)] public class Text : GameWindow { - Font serif2 = new Font(FontFamily.GenericSerif, 16.0f); - TextureFont serif = new TextureFont(new Font(FontFamily.GenericSerif, 12.0f)); - TextureFont sans = new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f)); - TextHandle poem_handle; + Font serif = new Font(FontFamily.GenericSerif, 16.0f); + Font sans = new Font(FontFamily.GenericSansSerif, 48.0f, FontStyle.Italic); TextPrinter text = new TextPrinter(); - string poem = new StreamReader("Data/Poem.txt").ReadToEnd(); + //string poem = new StreamReader("Data/Poem.txt").ReadToEnd(); + string poem = "The quick brown fox jumped over the lazy dogs!\n\nKerning: Wo\nLigatures: ffi, fft"; int lines; // How many lines the poem contains. float scroll_speed; @@ -49,7 +48,6 @@ namespace Examples.Tutorial current_position = initial_position; scroll_speed = -1.0f; - text.Prepare(poem, serif, out poem_handle); // Count the amount of lines in the text, to find out the correct // warparound position. We want the text to scroll until the last @@ -69,8 +67,10 @@ namespace Examples.Tutorial public override void OnUnload(EventArgs e) { - if (poem_handle != null) poem_handle.Dispose(); - if (serif != null) serif.Dispose(); + if (serif != null) + serif.Dispose(); + if (sans != null) + sans.Dispose(); } #endregion @@ -126,14 +126,17 @@ namespace Examples.Tutorial // used in 2d graphics, and is necessary for achieving pixel-perfect glyph rendering. // TextPrinter.End() restores your previous projection/modelview matrices. text.Begin(); - //GL.Color3(Color.LightBlue); - //text.Draw((1.0 / e.Time).ToString("F2"), sans); + + // Print FPS counter. Since the counter changes per frame, + // it shouldn't be cached (TextPrinterOptions.NoCache). + GL.Color3(Color.LightYellow); + text.Print((1.0 / e.Time).ToString("F2"), sans, TextPrinterOptions.NoCache); + + // Print the actual text. GL.Translate(0.0f, current_position, 0.0f); GL.Color3(Color.White); - //text.Draw(poem_handle); - //text.Draw(poem, serif); - //GL.BindTexture(TextureTarget.Texture2D, 1); - text.Print(poem, serif2); + text.Print(poem, serif); + text.End(); SwapBuffers(); From d3b57e6c5aaa7495de92333ebb2c596c9028b82e Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 18:00:17 +0000 Subject: [PATCH 17/53] Removed the old TextPrinter implementation. --- Source/Utilities/Fonts/TextPrinter.cs | 324 ++------------------------ 1 file changed, 22 insertions(+), 302 deletions(-) diff --git a/Source/Utilities/Fonts/TextPrinter.cs b/Source/Utilities/Fonts/TextPrinter.cs index e1bc9f93..056c7a81 100644 --- a/Source/Utilities/Fonts/TextPrinter.cs +++ b/Source/Utilities/Fonts/TextPrinter.cs @@ -28,277 +28,42 @@ namespace OpenTK.Graphics /// public sealed class TextPrinter : ITextPrinter { - //static Regex break_point = new Regex("[ .,/*-+?\\!=]", RegexOptions.Compiled | RegexOptions.IgnoreCase); - //static char[] split_chars = new char[] - //{ - // ' ', '\n', '\t', ',', '.', '/', '?', '!', ';', '\\', '-', '+', '*', '=' - //}; - static ITextPrinterImplementation printer; + #region Fields + + GlyphCache glyph_cache; + IGlyphRasterizer glyph_rasterizer; + ITextOutputProvider text_output; + float[] viewport = new float[4]; - // Interleaved, vertex, texcoord, vertex, etc... Starts with 8 chars, will expand as needed. - Vector2[] vertices = new Vector2[8 * 8]; - ushort[] indices = new ushort[6 * 8]; - List ranges = new List(); - - - #region --- Constructors --- - - public TextPrinter(ITextPrinterImplementation implementation) - { - if (implementation == null) - throw new ArgumentNullException("implementation"); - printer = implementation; - } #endregion - #region --- Private Members --- - - #region static ITextPrinterImplementation Printer + #region Constructors /// - /// Checks the machine's capabilities and selects the fastest method to print text. + /// Constructs a new TextPrinter object. /// - static ITextPrinterImplementation Printer + public TextPrinter() + : this(null, null) { - get - { - if (printer == null) - { + } - printer = (ITextPrinterImplementation)new DisplayListTextPrinter(); - //GL.SupportsExtension("VERSION_1_5") ? - //(ITextPrinterImplementation)new VboTextPrinter() : - //GL.SupportsExtension("ARB_vertex_buffer_object") ? null : - //GL.SupportsExtension("VERSION_1_1") ? null : null; - if (printer == null) - throw new NotSupportedException("TextPrinter requires at least OpenGL 1.1 support."); + TextPrinter(IGlyphRasterizer rasterizer, ITextOutputProvider output/*, IGlyphCacheProvider, ITextOutputProvider */) + { + if (rasterizer == null) + rasterizer = new GdiPlusGlyphRasterizer(); - Debug.Print("Using {0} for font printing.", printer); - } - return printer; - } + if (output == null) + output = new GL1TextOutputProvider(); + + glyph_rasterizer = rasterizer; + glyph_cache = new GlyphCache(rasterizer); + text_output = output; } #endregion - #endregion - - #region --- ITextPrinter Members --- - - #region public void Prepare(string text, TextureFont font, out TextHandle handle) - - /// - /// Prepares text for drawing. - /// - /// The string to draw. - /// The font to use for drawing. - /// The handle to the cached text. Use this to draw the text with the Draw() function. - /// - public void Prepare(string text, TextureFont font, out TextHandle handle) - { - this.Prepare(text, font, out handle, 0, false, StringAlignment.Near, false); - } - - #endregion - - #region public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp) - - /// - /// Prepares text for drawing. - /// - /// The string to draw. - /// The font to use for drawing. - /// The handle to the cached text. Use this to draw the text with the Draw() function. - /// Not implemented. - /// Not implemented. - /// - public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp) - { - this.Prepare(text, font, out handle, width, wordWarp, StringAlignment.Near, false); - } - - #endregion - - #region public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment) - - /// - /// Prepares text for drawing. - /// - /// The string to draw. - /// The font to use for drawing. - /// The handle to the cached text. Use this to draw the text with the Draw() function. - /// Not implemented. - /// Not implemented. - /// Not implemented. - /// - public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment) - { - this.Prepare(text, font, out handle, width, wordWarp, alignment, false); - } - - #endregion - - #region public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment, bool rightToLeft) - - /// - /// Prepares text for drawing. - /// - /// The string to draw. - /// The font to use for drawing. - /// The handle to the cached text. Use this to draw the text with the Draw() function. - /// Not implemented. - /// Not implemented. - /// Not implemented. - /// Not implemented. - /// - /// Occurs when OpenGL 1.1 is not supported. - public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment, bool rightToLeft) - { - int num_indices; - - PerformLayout(text, font, width, wordWarp, alignment, rightToLeft, ref vertices, ref indices, out num_indices); - - handle = Printer.Load(vertices, indices, num_indices); - handle.Font = font; - } - - #endregion - - #region void PerformLayout(string text, TextureFont font, float width, bool wordWarp, StringAlignment alignment, bool rightToLeft, ref Vector2[] vertices, ref ushort[] indices, out int num_indices) - - // Performs layout on the given string. - void PerformLayout(string text, TextureFont font, float width, bool wordWarp, StringAlignment alignment, - bool rightToLeft, ref Vector2[] vertices, ref ushort[] indices, out int num_indices) - { - if (text == null) - throw new ArgumentNullException("Parameter cannot be null.", "text"); - - if (text.Length > 8192) - throw new ArgumentOutOfRangeException("text", text.Length, "Text length must be between 1 and 8192 characters"); - - if (wordWarp || rightToLeft || alignment != StringAlignment.Near) - throw new NotImplementedException(); - - if (8 * text.Length > vertices.Length) - vertices = new Vector2[Math.Functions.NextPowerOfTwo(8 * text.Length)]; - - if (6 * text.Length > indices.Length) - indices = new ushort[Math.Functions.NextPowerOfTwo(6 * text.Length)]; - - num_indices = 6 * text.Length; - - //Vector2[] vertices = new Vector2[8 * text.Length]; // Interleaved, vertex, texcoord, vertex, etc... - //ushort[] indices = new ushort[6 * text.Length]; - float x_pos = 0, y_pos = 0; - ushort i = 0, index_count = 0, vertex_count = 0; - RectangleF rect = new RectangleF(); - float char_width, char_height; - int texture; - - font.LoadGlyphs(text); - - // Every character comprises of 4 vertices, forming two triangles. We generate an index array which - // indexes vertices in a triangle-list fashion. - // This algorithm works for left-to-right scripts. - - if (alignment == StringAlignment.Near && !rightToLeft || alignment == StringAlignment.Far && rightToLeft) - { - font.MeasureText(text, SizeF.Empty, null, ranges); - - int current = 0; - - foreach (char c in text) - { - if (c == '\n' || c == '\r') - continue; - else if (Char.IsWhiteSpace(c)) - { - current++; - continue; - } - - RectangleF range = ranges[current++]; - - x_pos = range.X; - y_pos = range.Y; - - font.GlyphData(c, out char_width, out char_height, out rect, out texture); - - vertices[vertex_count].X = x_pos; // Vertex - vertices[vertex_count++].Y = y_pos; - vertices[vertex_count].X = rect.Left; // Texcoord - vertices[vertex_count++].Y = rect.Top; - vertices[vertex_count].X = x_pos; // Vertex - vertices[vertex_count++].Y = y_pos + char_height; - vertices[vertex_count].X = rect.Left; // Texcoord - vertices[vertex_count++].Y = rect.Bottom; - - vertices[vertex_count].X = x_pos + char_width; // Vertex - vertices[vertex_count++].Y = y_pos + char_height; - vertices[vertex_count].X = rect.Right; // Texcoord - vertices[vertex_count++].Y = rect.Bottom; - vertices[vertex_count].X = x_pos + char_width; // Vertex - vertices[vertex_count++].Y = y_pos; - vertices[vertex_count].X = rect.Right; // Texcoord - vertices[vertex_count++].Y = rect.Top; - - indices[index_count++] = (ushort)(vertex_count - 8); - indices[index_count++] = (ushort)(vertex_count - 6); - indices[index_count++] = (ushort)(vertex_count - 4); - - indices[index_count++] = (ushort)(vertex_count - 4); - indices[index_count++] = (ushort)(vertex_count - 2); - indices[index_count++] = (ushort)(vertex_count - 8); - - ++i; - } - } - else if (alignment != StringAlignment.Center) - { - throw new NotImplementedException("This feature is not yet implemented. Sorry for the inconvenience."); - } - else - { - throw new NotImplementedException("This feature is not yet implemented. Sorry for the inconvenience."); - } - } - - #endregion - - #region public void Draw(TextHandle handle) - - /// - /// Draws the cached text referred to by the TextHandle. - /// - /// The TextHandle to the cached text. - public void Draw(TextHandle handle) - { - GL.BindTexture(TextureTarget.Texture2D, handle.Font.Texture); - - Printer.Draw(handle); - } - - #endregion - - #region public void Draw(string text, TextureFont font) - - /// - /// Draws dynamic text without caching. Not implemented yet! - /// - /// The System.String to draw. - /// The OpenTK.Graphics.TextureFont to draw the text in. - public void Draw(string text, TextureFont font) - { - int num_indices; - PerformLayout(text, font, 0, false, StringAlignment.Near, false, ref vertices, ref indices, out num_indices); - - GL.BindTexture(TextureTarget.Texture2D, font.Texture); - - Printer.Draw(vertices, indices, num_indices); - } - - #endregion + #region ITextPrinter Members #region public void Begin() @@ -354,49 +119,6 @@ namespace OpenTK.Graphics #endregion - #endregion - - #region New Implementation - - #region Fields - - Dictionary font_cache = new Dictionary(); - - GlyphCache glyph_cache; - IGlyphRasterizer glyph_rasterizer; - ITextOutputProvider text_output; - - //TextExtents text_extents = new TextExtents(); - - #endregion - - #region Constructors - - /// - /// Constructs a new TextPrinter object. - /// - public TextPrinter() - : this(null, null) - { - } - - TextPrinter(IGlyphRasterizer rasterizer, ITextOutputProvider output/*, IGlyphCacheProvider, ITextOutputProvider */) - { - if (rasterizer == null) - rasterizer = new GdiPlusGlyphRasterizer(); - - if (output == null) - output = new GL1TextOutputProvider(); - - glyph_rasterizer = rasterizer; - glyph_cache = new GlyphCache(rasterizer); - text_output = output; - } - - #endregion - - #region Public Members - #region Print public void Print(string text, Font font) @@ -521,7 +243,5 @@ namespace OpenTK.Graphics #endregion #endregion - - #endregion } } From c439904f70ba366f2ac521fe5e743b69731cd1c5 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 18:02:11 +0000 Subject: [PATCH 18/53] Moved to OpenTK.Graphics.Text namespace, along with the rest of the text printing stuff. --- .../Graphics/Text/CachedGlyphInfo.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Source/Utilities/Graphics/Text/CachedGlyphInfo.cs diff --git a/Source/Utilities/Graphics/Text/CachedGlyphInfo.cs b/Source/Utilities/Graphics/Text/CachedGlyphInfo.cs new file mode 100644 index 00000000..b9bbf62b --- /dev/null +++ b/Source/Utilities/Graphics/Text/CachedGlyphInfo.cs @@ -0,0 +1,62 @@ +#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 +{ + struct CachedGlyphInfo + { + public readonly Texture2D Texture; + public readonly RectangleF RectangleNormalized; + public Rectangle Rectangle + { + get + { + return new Rectangle( + (int)(RectangleNormalized.X * Texture.Width), + (int)(RectangleNormalized.Y * Texture.Height), + (int)(RectangleNormalized.Width * Texture.Width), + (int)(RectangleNormalized.Height * Texture.Height)); + } + } + + // Rect denotes the absolute position of the glyph in the texture [0, Texture.Width], [0, Texture.Height]. + public CachedGlyphInfo(Texture2D texture, Rectangle rect) + { + Texture = texture; + RectangleNormalized = new RectangleF( + rect.X / (float)texture.Width, + rect.Y / (float)texture.Height, + rect.Width / (float)texture.Width, + rect.Height / (float)texture.Height); + } + } +} From 7f15357835a608fd89e9b58c9415cb5d5d38b2dc Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 18:03:11 +0000 Subject: [PATCH 19/53] --- Source/Utilities/Graphics/CachedGlyphInfo.cs | 62 -------------------- 1 file changed, 62 deletions(-) delete mode 100644 Source/Utilities/Graphics/CachedGlyphInfo.cs diff --git a/Source/Utilities/Graphics/CachedGlyphInfo.cs b/Source/Utilities/Graphics/CachedGlyphInfo.cs deleted file mode 100644 index d5ff0f05..00000000 --- a/Source/Utilities/Graphics/CachedGlyphInfo.cs +++ /dev/null @@ -1,62 +0,0 @@ -#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 -{ - struct CachedGlyphInfo - { - public readonly Texture2D Texture; - public readonly RectangleF RectangleNormalized; - public Rectangle Rectangle - { - get - { - return new Rectangle( - (int)(RectangleNormalized.X * Texture.Width), - (int)(RectangleNormalized.Y * Texture.Height), - (int)(RectangleNormalized.Width * Texture.Width), - (int)(RectangleNormalized.Height * Texture.Height)); - } - } - - // Rect denotes the absolute position of the glyph in the texture [0, Texture.Width], [0, Texture.Height]. - public CachedGlyphInfo(Texture2D texture, Rectangle rect) - { - Texture = texture; - RectangleNormalized = new RectangleF( - rect.X / (float)texture.Width, - rect.Y / (float)texture.Height, - rect.Width / (float)texture.Width, - rect.Height / (float)texture.Height); - } - } -} From 4ca288bc87c9ee7b56bab33565127be6087c34ed Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 18:05:10 +0000 Subject: [PATCH 20/53] Moved to Graphics folder along with the rest of the implementation. --- Source/Utilities/{Fonts => Graphics}/ITextPrinter.cs | 0 Source/Utilities/{Fonts => Graphics}/TextPrinter.cs | 0 Source/Utilities/{Fonts => Graphics}/TextPrinterOptions.cs | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename Source/Utilities/{Fonts => Graphics}/ITextPrinter.cs (100%) rename Source/Utilities/{Fonts => Graphics}/TextPrinter.cs (100%) rename Source/Utilities/{Fonts => Graphics}/TextPrinterOptions.cs (100%) diff --git a/Source/Utilities/Fonts/ITextPrinter.cs b/Source/Utilities/Graphics/ITextPrinter.cs similarity index 100% rename from Source/Utilities/Fonts/ITextPrinter.cs rename to Source/Utilities/Graphics/ITextPrinter.cs diff --git a/Source/Utilities/Fonts/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs similarity index 100% rename from Source/Utilities/Fonts/TextPrinter.cs rename to Source/Utilities/Graphics/TextPrinter.cs diff --git a/Source/Utilities/Fonts/TextPrinterOptions.cs b/Source/Utilities/Graphics/TextPrinterOptions.cs similarity index 100% rename from Source/Utilities/Fonts/TextPrinterOptions.cs rename to Source/Utilities/Graphics/TextPrinterOptions.cs From 27c3f3b0ce2bb10803683473dcaa59b886b8a736 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 18:17:30 +0000 Subject: [PATCH 21/53] Obsoleted old implementation and added compatibility layer to the new ITextPrinter. --- .../Utilities/Fonts/DisplayListTextHandle.cs | 1 + .../Utilities/Fonts/DisplayListTextPrinter.cs | 1 + Source/Utilities/Fonts/Glyph.cs | 1 + .../Utilities/Fonts/IPrinterImplementation.cs | 1 + Source/Utilities/Fonts/TextHandle.cs | 14 ++++++++++-- Source/Utilities/Fonts/TextureFont.cs | 5 +++-- Source/Utilities/Fonts/VboTextPrinter.cs | 2 ++ Source/Utilities/Graphics/ITextPrinter.cs | 9 ++++++++ Source/Utilities/Graphics/TextPrinter.cs | 22 +++++++++++++++++++ 9 files changed, 52 insertions(+), 4 deletions(-) diff --git a/Source/Utilities/Fonts/DisplayListTextHandle.cs b/Source/Utilities/Fonts/DisplayListTextHandle.cs index 192c8c7d..c1a00ebf 100644 --- a/Source/Utilities/Fonts/DisplayListTextHandle.cs +++ b/Source/Utilities/Fonts/DisplayListTextHandle.cs @@ -11,6 +11,7 @@ using OpenTK.Graphics.OpenGL; namespace OpenTK.Graphics { + [Obsolete()] class DisplayListTextHandle : TextHandle { public DisplayListTextHandle(int handle) : base(handle) { } diff --git a/Source/Utilities/Fonts/DisplayListTextPrinter.cs b/Source/Utilities/Fonts/DisplayListTextPrinter.cs index 5958dc35..835f9f1a 100644 --- a/Source/Utilities/Fonts/DisplayListTextPrinter.cs +++ b/Source/Utilities/Fonts/DisplayListTextPrinter.cs @@ -16,6 +16,7 @@ namespace OpenTK.Graphics /// /// Provides text printing through OpenGL 1.1 Display Lists. /// + [Obsolete()] class DisplayListTextPrinter : ITextPrinterImplementation { #region IPrinter Members diff --git a/Source/Utilities/Fonts/Glyph.cs b/Source/Utilities/Fonts/Glyph.cs index c64acfe5..d124e2cc 100644 --- a/Source/Utilities/Fonts/Glyph.cs +++ b/Source/Utilities/Fonts/Glyph.cs @@ -16,6 +16,7 @@ namespace OpenTK.Graphics /// /// Represents a single character of a specific Font. /// + [Obsolete] struct Glyph : IPackable { char character; diff --git a/Source/Utilities/Fonts/IPrinterImplementation.cs b/Source/Utilities/Fonts/IPrinterImplementation.cs index c849ed1f..0f901f10 100644 --- a/Source/Utilities/Fonts/IPrinterImplementation.cs +++ b/Source/Utilities/Fonts/IPrinterImplementation.cs @@ -15,6 +15,7 @@ namespace OpenTK.Graphics /// /// Defines the interface for TextPrinter implementations. /// + [Obsolete("Use ITextOutputProvider instead")] public interface ITextPrinterImplementation { /// diff --git a/Source/Utilities/Fonts/TextHandle.cs b/Source/Utilities/Fonts/TextHandle.cs index fdb48f7b..321ff14a 100644 --- a/Source/Utilities/Fonts/TextHandle.cs +++ b/Source/Utilities/Fonts/TextHandle.cs @@ -13,17 +13,27 @@ namespace OpenTK.Graphics /// /// Represents a handle to cached text. /// - public abstract class TextHandle : IDisposable + [Obsolete("Use TextPrinter.Print instead")] + public class TextHandle : IDisposable { + internal string Text; + internal System.Drawing.Font GdiPFont; + /// /// Constructs a new TextHandle, /// /// - public TextHandle(int handle) + internal TextHandle(int handle) { Handle = handle; } + internal TextHandle(string text, System.Drawing.Font font) + { + Text = text; + GdiPFont = font; + } + private int handle; protected TextureFont font; protected bool disposed; diff --git a/Source/Utilities/Fonts/TextureFont.cs b/Source/Utilities/Fonts/TextureFont.cs index 6d30ce9f..dee839de 100644 --- a/Source/Utilities/Fonts/TextureFont.cs +++ b/Source/Utilities/Fonts/TextureFont.cs @@ -21,11 +21,12 @@ namespace OpenTK.Graphics { using Graphics = System.Drawing.Graphics; using PixelFormat = OpenTK.Graphics.PixelFormat; -using System.Text.RegularExpressions; + using System.Text.RegularExpressions; + [Obsolete("Use System.Drawing.Font instead")] public class TextureFont : IFont { - Font font; + internal Font font; Dictionary loaded_glyphs = new Dictionary(64); Bitmap bmp; diff --git a/Source/Utilities/Fonts/VboTextPrinter.cs b/Source/Utilities/Fonts/VboTextPrinter.cs index 3c4a5731..f6c37a0a 100644 --- a/Source/Utilities/Fonts/VboTextPrinter.cs +++ b/Source/Utilities/Fonts/VboTextPrinter.cs @@ -17,6 +17,7 @@ namespace OpenTK.Graphics /// /// Provides text printing through OpenGL 1.5 vertex buffer objects. /// + [Obsolete] class VboTextPrinter : ITextPrinterImplementation { static int allocated_handles; @@ -84,6 +85,7 @@ namespace OpenTK.Graphics /// /// Contains the necessary information to print text through the VboTextPrinter implementation. /// + [Obsolete] class VboTextHandle : TextHandle { public VboTextHandle(int handle) : base(handle) { } diff --git a/Source/Utilities/Graphics/ITextPrinter.cs b/Source/Utilities/Graphics/ITextPrinter.cs index c39b46bf..717b2870 100644 --- a/Source/Utilities/Graphics/ITextPrinter.cs +++ b/Source/Utilities/Graphics/ITextPrinter.cs @@ -25,5 +25,14 @@ namespace OpenTK.Graphics TextExtents Measure(string text, Font font); TextExtents Measure(string text, Font font, TextPrinterOptions options); TextExtents Measure(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle); + + [Obsolete("Use TextPrinter.Print instead")] + void Draw(TextHandle handle); + + [Obsolete("Use TextPrinter.Print instead")] + void Draw(string text, TextureFont font); + + [Obsolete("Use TextPrinter.Print instead")] + void Prepare(string text, TextureFont font, out TextHandle handle); } } diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index 056c7a81..86d5d8a2 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -177,6 +177,28 @@ namespace OpenTK.Graphics #endregion + #region Obsolete + + [Obsolete("Use TextPrinter.Print instead")] + public void Draw(TextHandle handle) + { + Print(handle.Text, handle.GdiPFont); + } + + [Obsolete("Use TextPrinter.Print instead")] + public void Draw(string text, TextureFont font) + { + Print(text, font.font); + } + + [Obsolete("Use TextPrinter.Print instead")] + public void Prepare(string text, TextureFont font, out TextHandle handle) + { + handle = new TextHandle(text, font.font); + } + + #endregion + #endregion #region Private Members From 2bffcbbfcf0a6124dd9cc55cb49fa0a2eda5be79 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 19:00:06 +0000 Subject: [PATCH 22/53] Added new font rendering sample. --- .../WinForms/FontRendering.Designer.cs | 94 +++++++++++++ Source/Examples/WinForms/FontRendering.cs | 115 ++++++++++++++++ Source/Examples/WinForms/FontRendering.resx | 123 ++++++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 Source/Examples/WinForms/FontRendering.Designer.cs create mode 100644 Source/Examples/WinForms/FontRendering.cs create mode 100644 Source/Examples/WinForms/FontRendering.resx diff --git a/Source/Examples/WinForms/FontRendering.Designer.cs b/Source/Examples/WinForms/FontRendering.Designer.cs new file mode 100644 index 00000000..c0b43c16 --- /dev/null +++ b/Source/Examples/WinForms/FontRendering.Designer.cs @@ -0,0 +1,94 @@ +namespace Examples.WinForms +{ + partial class FontRendering + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.glControl1 = new OpenTK.GLControl(); + this.changeFont = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.fontDialog = new System.Windows.Forms.FontDialog(); + this.SuspendLayout(); + // + // glControl1 + // + this.glControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.glControl1.BackColor = System.Drawing.Color.Black; + this.glControl1.Location = new System.Drawing.Point(0, 40); + this.glControl1.Name = "glControl1"; + this.glControl1.Size = new System.Drawing.Size(700, 521); + this.glControl1.TabIndex = 0; + this.glControl1.VSync = false; + this.glControl1.Load += new System.EventHandler(this.glControl1_Load); + this.glControl1.Paint += new System.Windows.Forms.PaintEventHandler(this.glControl1_Paint); + this.glControl1.Resize += new System.EventHandler(this.glControl1_Resize); + // + // changeFont + // + this.changeFont.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.changeFont.Location = new System.Drawing.Point(568, 10); + this.changeFont.Name = "changeFont"; + this.changeFont.Size = new System.Drawing.Size(120, 23); + this.changeFont.TabIndex = 1; + this.changeFont.Text = "Change Font"; + this.changeFont.UseVisualStyleBackColor = true; + this.changeFont.Click += new System.EventHandler(this.changeFont_Click); + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(12, 11); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(550, 22); + this.textBox1.TabIndex = 2; + this.textBox1.Text = "The quick fox jumped over the lazy dogs. 0123456789"; + this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged); + // + // FontRendering + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(700, 561); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.changeFont); + this.Controls.Add(this.glControl1); + this.Name = "FontRendering"; + this.Text = "FontRendering"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private OpenTK.GLControl glControl1; + private System.Windows.Forms.Button changeFont; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.FontDialog fontDialog; + } +} \ No newline at end of file diff --git a/Source/Examples/WinForms/FontRendering.cs b/Source/Examples/WinForms/FontRendering.cs new file mode 100644 index 00000000..1d18a438 --- /dev/null +++ b/Source/Examples/WinForms/FontRendering.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using OpenTK.Graphics; + +namespace Examples.WinForms +{ + [Example("Font rendering sample", ExampleCategory.WinForms)] + public partial class FontRendering : Form + { + #region Fields + + float[] sizes = new float[] { 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 48 }; + List fonts = new List(); + + TextPrinter text = new TextPrinter(); + + #endregion + + #region Constructors + + public FontRendering() + { + InitializeComponent(); + + UpdateFontList(fontDialog.Font); + glControl1_Resize(this, EventArgs.Empty); + } + + #endregion + + #region Private Members + + void UpdateFontList(Font base_font) + { + foreach (Font font in fonts) + font.Dispose(); + fonts.Clear(); + foreach (float size in sizes) + fonts.Add(new Font(base_font.Name, size, base_font.Style)); + } + + #endregion + + #region Events + + private void glControl1_Load(object sender, EventArgs e) + { + GL.ClearColor(Color.SteelBlue); + } + + private void changeFont_Click(object sender, EventArgs e) + { + if (fontDialog.ShowDialog() == DialogResult.OK) + { + UpdateFontList(fontDialog.Font); + } + } + + + private void textBox1_TextChanged(object sender, EventArgs e) + { + glControl1.Invalidate(); + } + + private void glControl1_Paint(object sender, PaintEventArgs e) + { + GL.Clear(ClearBufferMask.ColorBufferBit); + GL.Color3(Color.White); + + text.Begin(); + + foreach (Font font in fonts) + { + text.Print(textBox1.Text, font); + GL.Translate(0, font.Height, 0); + } + + text.End(); + + glControl1.SwapBuffers(); + } + + private void glControl1_Resize(object sender, EventArgs e) + { + if (glControl1.ClientSize.Height == 0) + glControl1.ClientSize = new System.Drawing.Size(glControl1.ClientSize.Width, 1); + + GL.Viewport(0, 0, glControl1.ClientSize.Width, glControl1.ClientSize.Height); + } + + #endregion + + #region public static void Main() + + /// + /// Entry point of this example. + /// + [STAThread] + public static void Main() + { + using (FontRendering example = new FontRendering()) + { + Utilities.SetWindowTitle(example); + example.ShowDialog(); + } + } + + #endregion + } +} diff --git a/Source/Examples/WinForms/FontRendering.resx b/Source/Examples/WinForms/FontRendering.resx new file mode 100644 index 00000000..11e8cf35 --- /dev/null +++ b/Source/Examples/WinForms/FontRendering.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file From 26af1aa354250dd173949183a88bda62566edadd Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 19:20:40 +0000 Subject: [PATCH 23/53] Fix text measurement for non-italic text. --- Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index cbe58047..9ca42400 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -80,7 +80,8 @@ namespace OpenTK.Graphics.Text { SetTextRenderingOptions(gfx, glyph.Font); - gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, load_glyph_string_format); + 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); } } @@ -130,6 +131,10 @@ namespace OpenTK.Graphics.Text { // Todo: Parse layout options: StringFormat format = default_string_format; + //if (block.Font.Style != FontStyle.Regular) + // format = load_glyph_string_format; + //else + // format = default_string_format; extents.Clear(); From afa76c9894025eb46b61650d43cddf670be14636 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 22:16:40 +0000 Subject: [PATCH 24/53] Removed unused code. Implemented Glyph enumerator for TextBlock. GdiPlusGlyphRasterizer.Rasterize now reuses its Bitmap surface, if possible. --- .../Graphics/Text/GL1TextOutputProvider.cs | 18 ++- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 36 ++++-- Source/Utilities/Graphics/Text/Glyph.cs | 13 ++- Source/Utilities/Graphics/Text/GlyphCache.cs | 45 +++----- .../Graphics/Text/GlyphEnumerator.cs | 107 ++++++++++++++++++ Source/Utilities/Graphics/Text/IGlyphCache.cs | 36 ++++++ Source/Utilities/Graphics/Text/TextBlock.cs | 25 +++- Source/Utilities/Graphics/TextPrinter.cs | 79 ------------- 8 files changed, 231 insertions(+), 128 deletions(-) create mode 100644 Source/Utilities/Graphics/Text/GlyphEnumerator.cs create mode 100644 Source/Utilities/Graphics/Text/IGlyphCache.cs 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 } } From a26b75f3af5ca25117da0ff9677121aea11fea38 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 25 Nov 2008 22:19:42 +0000 Subject: [PATCH 25/53] IGlyphCache.Contains should return bool, not void. GlyphCache now implements the IGlyphCache interface. --- Source/Utilities/Graphics/Text/GlyphCache.cs | 4 ++-- Source/Utilities/Graphics/Text/IGlyphCache.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Utilities/Graphics/Text/GlyphCache.cs b/Source/Utilities/Graphics/Text/GlyphCache.cs index d09b508f..1b943110 100644 --- a/Source/Utilities/Graphics/Text/GlyphCache.cs +++ b/Source/Utilities/Graphics/Text/GlyphCache.cs @@ -31,7 +31,7 @@ using System.Drawing; namespace OpenTK.Graphics.Text { - class GlyphCache// : IGlyphCache + class GlyphCache : IGlyphCache { #region Fields @@ -56,7 +56,7 @@ namespace OpenTK.Graphics.Text #endregion - #region Public Members + #region IGlyphCache Members public void Add(Glyph glyph) { diff --git a/Source/Utilities/Graphics/Text/IGlyphCache.cs b/Source/Utilities/Graphics/Text/IGlyphCache.cs index d65c23c4..49195888 100644 --- a/Source/Utilities/Graphics/Text/IGlyphCache.cs +++ b/Source/Utilities/Graphics/Text/IGlyphCache.cs @@ -30,7 +30,7 @@ namespace OpenTK.Graphics.Text interface IGlyphCache { void Add(Glyph glyph); - void Contains(Glyph glyph); + bool Contains(Glyph glyph); CachedGlyphInfo this[Glyph glyph] { get; } } } From a868c4b4e8d93904968bf965e96fa1efd59d30bf Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Wed, 26 Nov 2008 15:35:15 +0000 Subject: [PATCH 26/53] Remove exceptions from the typical path (significant speed increase). --- Source/Utilities/Graphics/Text/GlyphCache.cs | 28 +++--- Source/Utilities/Graphics/Text/GlyphPacker.cs | 91 +++++++++++++------ 2 files changed, 74 insertions(+), 45 deletions(-) diff --git a/Source/Utilities/Graphics/Text/GlyphCache.cs b/Source/Utilities/Graphics/Text/GlyphCache.cs index 1b943110..fa99e041 100644 --- a/Source/Utilities/Graphics/Text/GlyphCache.cs +++ b/Source/Utilities/Graphics/Text/GlyphCache.cs @@ -37,7 +37,7 @@ namespace OpenTK.Graphics.Text IGlyphRasterizer rasterizer; List sheets = new List(); - Bitmap bmp = new Bitmap(256, 256); + Bitmap bmp = new Bitmap(32, 32); Dictionary cached_glyphs = new Dictionary(); @@ -64,24 +64,19 @@ namespace OpenTK.Graphics.Text using (Bitmap bmp = rasterizer.Rasterize(glyph)) { + Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); foreach (GlyphSheet sheet in sheets) { - try - { - InsertGlyph(glyph, bmp, sheet); - inserted = true; - break; - } - catch (TexturePackerFullException) - { - } + inserted = InsertGlyph(glyph, bmp, rect, sheet); + if (inserted) + break; } if (!inserted) { GlyphSheet sheet = new GlyphSheet(); sheets.Add(sheet); - InsertGlyph(glyph, bmp, sheet); + InsertGlyph(glyph, bmp, rect, sheet); } } } @@ -103,14 +98,17 @@ namespace OpenTK.Graphics.Text #region Private Members - void InsertGlyph(Glyph glyph, Bitmap bmp, GlyphSheet sheet) + // Asks the packer for an empty space and writes the glyph there. + bool InsertGlyph(Glyph glyph, Bitmap bmp, Rectangle source, GlyphSheet sheet) { - Rectangle source = new Rectangle(0, 0, bmp.Width, bmp.Height); - Rectangle target = sheet.Packer.Add(source); + Rectangle target = new Rectangle(); + if (!sheet.Packer.TryAdd(source, out target)) + return false; sheet.Texture.WriteRegion(source, target, 0, bmp); - cached_glyphs.Add(glyph, new CachedGlyphInfo(sheet.Texture, target)); + + return true; } #endregion diff --git a/Source/Utilities/Graphics/Text/GlyphPacker.cs b/Source/Utilities/Graphics/Text/GlyphPacker.cs index dd3ccb80..9cda0dd0 100644 --- a/Source/Utilities/Graphics/Text/GlyphPacker.cs +++ b/Source/Utilities/Graphics/Text/GlyphPacker.cs @@ -53,6 +53,64 @@ namespace OpenTK.Graphics.Text #region --- Public Methods --- + #region public bool TryAdd(Rectangle boundingBox) + + /// + /// Adds boundingBox to the GlyphPacker. + /// + /// The bounding box of the item to pack. + /// The System.Drawing.Rectangle that contains the position of the packed item. + /// True, if the item was successfully packed; false if the item is too big for this packer.. + /// Occurs if the item is larger than the available TexturePacker area + /// Occurs if the item cannot fit in the remaining packer space. + public bool TryAdd(Rectangle boundingBox, out Rectangle packedRectangle) + { + if (!root.Rectangle.Contains(boundingBox)) + { + packedRectangle = new Rectangle(); + return false; + } + + // Increase size so that the glyphs do not touch each other (to avoid rendering artifacts). + boundingBox.Width += 2; + boundingBox.Height += 2; + + Node node = root.Insert(boundingBox); + + // Tree is full and insertion failed: + if (node == null) + { + packedRectangle = new Rectangle(); + return false; + } + + packedRectangle = new Rectangle(node.Rectangle.X, node.Rectangle.Y, node.Rectangle.Width - 2, node.Rectangle.Height - 2); + return true; + } + + #endregion + + #region public Rectangle TryAdd(RectangleF boundingBox) + + /// + /// Adds boundingBox to the GlyphPacker. + /// + /// The bounding box of the item to pack. + /// The System.Drawing.RectangleF that contains the position of the packed item. + /// True, if the item was successfully packed; false if the item is too big for this packer.. + /// Occurs if the item is larger than the available TexturePacker area + /// Occurs if the item cannot fit in the remaining packer space. + public bool TryAdd(RectangleF boundingBox, out RectangleF packedRectangle) + { + Rectangle bbox = new Rectangle( + (int)boundingBox.X, (int)boundingBox.Y, + (int)(boundingBox.Width + 0.5f), (int)(boundingBox.Height + 0.5f)); + + return TryAdd(bbox, out packedRectangle); + } + + #endregion + #region public Rectangle Add(Rectangle boundingBox) /// @@ -61,24 +119,13 @@ namespace OpenTK.Graphics.Text /// The bounding box of the item to pack. /// A System.Drawing.Rectangle containing the coordinates of the packed item. /// Occurs if the item is larger than the available TexturePacker area - /// Occurs if the item already exists in the TexturePacker. + /// Occurs if the item cannot fit in the remaining packer space. public Rectangle Add(Rectangle boundingBox) { - if (!root.Rectangle.Contains(boundingBox)) - throw new InvalidOperationException("The item is too large for this TexturePacker"); - - Node node; - // Increase size so that the glyphs do not touch each other (to avoid rendering artifacts). - boundingBox.Width += 2; - boundingBox.Height += 2; - node = root.Insert(boundingBox); - - // Tree is full and insertion failed: - if (node == null) + if (!TryAdd(boundingBox, out boundingBox)) throw new TexturePackerFullException(); - return new Rectangle(node.Rectangle.X, node.Rectangle.Y, node.Rectangle.Width - 2, node.Rectangle.Height - 2); - //return node.Rectangle; + return boundingBox; } #endregion @@ -115,22 +162,6 @@ namespace OpenTK.Graphics.Text #endregion - #region public void ChangeSize(int new_width, int new_height) - - /// - /// Changes the dimensions of the TexturePacker surface. - /// - /// The new width of the TexturePacker surface. - /// The new height of the TexturePacker surface. - /// Changing the size of the TexturePacker surface will implicitly call TexturePacker.Clear(). - /// - public void ChangeSize(int new_width, int new_height) - { - throw new NotImplementedException(); - } - - #endregion - #endregion #region Node From c0549b11fa41cac3efb7dee0826c04e6fadc0a33 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Wed, 26 Nov 2008 16:34:50 +0000 Subject: [PATCH 27/53] Fixed TextExtents behavior when returning either cached or uncached instances. Reduced memory pressure by adding object pooling to TextExtents. --- .../Graphics/Text/GL1TextOutputProvider.cs | 105 +++++++++--------- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 86 ++++++++++---- .../Graphics/Text/IGlyphRasterizer.cs | 1 + .../Graphics/Text/PoolableTextExtents.cs | 42 +++++++ Source/Utilities/Graphics/Text/TextExtents.cs | 48 ++++---- Source/Utilities/IPoolable.cs | 17 +++ Source/Utilities/ObjectPool.cs | 42 +++++++ 7 files changed, 246 insertions(+), 95 deletions(-) create mode 100644 Source/Utilities/Graphics/Text/PoolableTextExtents.cs create mode 100644 Source/Utilities/IPoolable.cs create mode 100644 Source/Utilities/ObjectPool.cs diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index 501a13c7..c75dbe9e 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -57,63 +57,64 @@ namespace OpenTK.Graphics.Text public void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache) { - TextExtents extents = rasterizer.MeasureText(block); - - //GL.BindTexture(TextureTarget.Texture2D, 2); - - //GL.Begin(BeginMode.Quads); - - //GL.TexCoord2(0, 0); - //GL.Vertex2(0, 0); - //GL.TexCoord2(1, 0); - //GL.Vertex2(256, 0); - //GL.TexCoord2(1, 1); - //GL.Vertex2(256, 256); - //GL.TexCoord2(0, 1); - //GL.Vertex2(0, 256); - - //GL.End(); - - //GL.Translate(0, 256, 0); - - // Build layout - int current = 0; - foreach (Glyph glyph in block) + using (TextExtents extents = rasterizer.MeasureText(block)) { - if (glyph.IsWhiteSpace) + //GL.BindTexture(TextureTarget.Texture2D, 2); + + //GL.Begin(BeginMode.Quads); + + //GL.TexCoord2(0, 0); + //GL.Vertex2(0, 0); + //GL.TexCoord2(1, 0); + //GL.Vertex2(256, 0); + //GL.TexCoord2(1, 1); + //GL.Vertex2(256, 256); + //GL.TexCoord2(0, 1); + //GL.Vertex2(0, 256); + + //GL.End(); + + //GL.Translate(0, 256, 0); + + // Build layout + int current = 0; + foreach (Glyph glyph in block) { - current++; - continue; - } - else if (!cache.Contains(glyph)) - cache.Add(glyph); + if (glyph.IsWhiteSpace) + { + current++; + continue; + } + else if (!cache.Contains(glyph)) + cache.Add(glyph); - 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). - position.Size = info.Rectangle.Size; + CachedGlyphInfo info = cache[glyph]; + RectangleF position = extents[current++]; - if (!active_lists.ContainsKey(info.Texture)) - if (inactive_lists.Count > 0) - active_lists.Add(info.Texture, inactive_lists.Dequeue()); - else - active_lists.Add(info.Texture, new List()); - { - // Interleaved array: Vertex, TexCoord, Vertex, ... - active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); - active_lists[info.Texture].Add(new Vector2(position.Left, position.Top)); - active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom)); - active_lists[info.Texture].Add(new Vector2(position.Left, position.Bottom)); - active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); - active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom)); + // Use the real glyph width instead of the measured one (we want to achieve pixel perfect output). + position.Size = info.Rectangle.Size; - active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); - active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom)); - active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Top)); - active_lists[info.Texture].Add(new Vector2(position.Right, position.Top)); - active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); - active_lists[info.Texture].Add(new Vector2(position.Left, position.Top)); + if (!active_lists.ContainsKey(info.Texture)) + if (inactive_lists.Count > 0) + active_lists.Add(info.Texture, inactive_lists.Dequeue()); + else + active_lists.Add(info.Texture, new List()); + { + // Interleaved array: Vertex, TexCoord, Vertex, ... + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); + active_lists[info.Texture].Add(new Vector2(position.Left, position.Top)); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom)); + active_lists[info.Texture].Add(new Vector2(position.Left, position.Bottom)); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); + active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom)); + + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); + active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom)); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Top)); + active_lists[info.Texture].Add(new Vector2(position.Right, position.Top)); + active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); + active_lists[info.Texture].Add(new Vector2(position.Left, position.Top)); + } } } diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index 8709bfc7..e1f722c9 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -34,6 +34,7 @@ using System.Drawing.Text; using OpenTK.Graphics.Text; using OpenTK.Platform; using System.Diagnostics; +using System.Drawing.Imaging; namespace OpenTK.Graphics.Text { @@ -47,11 +48,11 @@ namespace OpenTK.Graphics.Text IntPtr[] regions = new IntPtr[GdiPlus.MaxMeasurableCharacterRanges]; CharacterRange[] characterRanges = new CharacterRange[GdiPlus.MaxMeasurableCharacterRanges]; - TextExtents extents = new TextExtents(); - Bitmap glyph_surface; System.Drawing.Graphics glyph_renderer; + readonly ObjectPool text_extents_pool = new ObjectPool(); + // Check the constructor, too, for additional flags. static readonly StringFormat default_string_format = StringFormat.GenericTypographic; static readonly StringFormat load_glyph_string_format = StringFormat.GenericDefault; @@ -78,6 +79,8 @@ namespace OpenTK.Graphics.Text public Bitmap Rasterize(Glyph glyph) { + RectangleF r = MeasureText(new TextBlock(glyph.Character.ToString(), glyph.Font, TextPrinterOptions.NoCache, RectangleF.Empty)).BoundingBox; + EnsureSurfaceSize(ref glyph_surface, ref glyph_renderer, glyph.Font); SetTextRenderingOptions(glyph_renderer, glyph.Font); @@ -85,7 +88,25 @@ namespace OpenTK.Graphics.Text 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); + + RectangleF r2 = FindEdges(glyph_surface); + + return glyph_surface.Clone(r2, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + } + + public void Rasterize(Glyph glyph, ref Bitmap bmp, out Rectangle rect) + { + EnsureSurfaceSize(ref bmp, ref glyph_renderer, glyph.Font); + + using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp)) + { + SetTextRenderingOptions(gfx, glyph.Font); + + gfx.Clear(Color.Transparent); + gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, + glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format); + rect = FindEdges(bmp); + } } #endregion @@ -99,10 +120,10 @@ namespace OpenTK.Graphics.Text if (block_cache.ContainsKey(block)) return block_cache[block]; - // If this block is not cached, we have to measure it and place it in the cache. - MeasureTextExtents(block, ref extents); + // If this block is not cached, we have to measure it and (potentially) place it in the cache. + TextExtents extents = MeasureTextExtents(block); if ((block.Options & TextPrinterOptions.NoCache) == 0) - block_cache.Add(block, new TextExtents(extents.BoundingBox, extents.GlyphExtents)); + block_cache.Add(block, extents); return extents; } @@ -147,7 +168,7 @@ namespace OpenTK.Graphics.Text #region MeasureTextExtents - void MeasureTextExtents(TextBlock block, ref TextExtents extents) + TextExtents MeasureTextExtents(TextBlock block) { // Todo: Parse layout options: StringFormat format = default_string_format; @@ -156,7 +177,7 @@ namespace OpenTK.Graphics.Text //else // format = default_string_format; - extents.Clear(); + TextExtents extents = text_extents_pool.Acquire(); PointF origin = PointF.Empty; SizeF size = SizeF.Empty; @@ -189,6 +210,8 @@ namespace OpenTK.Graphics.Text } extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, extents[extents.Count - 1].Right, extents[extents.Count - 1].Bottom); + + return extents; } #endregion @@ -252,13 +275,28 @@ namespace OpenTK.Graphics.Text #region FindEdges + #pragma warning disable 0649 + + struct Pixel { public byte B, G, R, A; } + + #pragma warning restore 0649 + Rectangle FindEdges(Bitmap bmp) { - return Rectangle.FromLTRB( - FindLeftEdge(bmp), - FindTopEdge(bmp), - FindRightEdge(bmp), - FindBottomEdge(bmp)); + BitmapData data = bmp.LockBits( + new Rectangle(0, 0, bmp.Width, bmp.Height), + ImageLockMode.ReadOnly, + System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + Rectangle rect = Rectangle.FromLTRB( + FindLeftEdge(bmp, data.Scan0), + FindTopEdge(bmp, data.Scan0), + FindRightEdge(bmp, data.Scan0), + FindBottomEdge(bmp, data.Scan0)); + + bmp.UnlockBits(data); + + return rect; } #endregion @@ -267,34 +305,40 @@ namespace OpenTK.Graphics.Text // Iterates through the bmp, and returns the first row or line that contains a non-transparent pixels. - int FindLeftEdge(Bitmap bmp) + int FindLeftEdge(Bitmap bmp, IntPtr ptr) { // Don't trim the left edge, because the layout engine expects it to be 0. return 0; } - int FindRightEdge(Bitmap bmp) + int FindRightEdge(Bitmap bmp, IntPtr ptr) { for (int x = bmp.Width - 1; x >= 0; x--) for (int y = 0; y < bmp.Height; y++) - if (bmp.GetPixel(x, y).A != 0) - return x + 1; + unsafe + { + if (((Pixel*)(ptr) + y * bmp.Width + x)->A != 0) + return x + 1; + } return 0; } - int FindTopEdge(Bitmap bmp) + int FindTopEdge(Bitmap bmp, IntPtr ptr) { // Don't trim the top edge, because the layout engine expects it to be 0. return 0; } - int FindBottomEdge(Bitmap bmp) + int FindBottomEdge(Bitmap bmp, IntPtr ptr) { for (int y = bmp.Height - 1; y >= 0; y--) for (int x = 0; x < bmp.Width; x++) - if (bmp.GetPixel(x, y).A != 0) - return y + 1; + unsafe + { + if (((Pixel*)(ptr) + y * bmp.Width + x)->A != 0) + return y + 1; + } return 0; } diff --git a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs index dc568191..d07f7429 100644 --- a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs +++ b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs @@ -38,5 +38,6 @@ namespace OpenTK.Graphics.Text { Bitmap Rasterize(Glyph glyph); TextExtents MeasureText(TextBlock block); + void Rasterize(Glyph glyph, ref Bitmap bmp, out Rectangle rect); } } diff --git a/Source/Utilities/Graphics/Text/PoolableTextExtents.cs b/Source/Utilities/Graphics/Text/PoolableTextExtents.cs new file mode 100644 index 00000000..7b7c74a0 --- /dev/null +++ b/Source/Utilities/Graphics/Text/PoolableTextExtents.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics.Text +{ + class PoolableTextExtents : TextExtents, IPoolable + { + ObjectPool owner; + + #region Constructors + + public PoolableTextExtents() + { + } + + #endregion + + #region IPoolable Members + + ObjectPool IPoolable.Owner + { + get { return owner; } + set { owner = value; } + } + + #endregion + + #region IPoolable Members + + void IPoolable.OnAcquire() + { + Clear(); + } + + void IPoolable.OnRelease() + { + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/TextExtents.cs b/Source/Utilities/Graphics/Text/TextExtents.cs index 3f646b4b..c8a241a7 100644 --- a/Source/Utilities/Graphics/Text/TextExtents.cs +++ b/Source/Utilities/Graphics/Text/TextExtents.cs @@ -33,31 +33,21 @@ using System.Drawing; namespace OpenTK.Graphics.Text { // Holds layout information about a TextBlock. - public struct TextExtents + public class TextExtents : IDisposable { #region Fields - RectangleF text_extents; - List glyph_extents; + protected RectangleF text_extents; + protected List glyph_extents = new List(); #endregion #region Constructors - public TextExtents(RectangleF bbox) - : this(bbox, null) + internal TextExtents() { } - public TextExtents(RectangleF bbox, IEnumerable glyphExtents) - : this() - { - BoundingBox = bbox; - - if (glyphExtents != null) - AddRange(glyphExtents); - } - #endregion #region Public Members @@ -70,23 +60,29 @@ namespace OpenTK.Graphics.Text public RectangleF this[int i] { - get { return (GlyphExtents as List)[i]; } - internal set { (GlyphExtents as List)[i] = value; } + get { return glyph_extents[i]; } + internal set { glyph_extents[i] = value; } } public IEnumerable GlyphExtents { get { - if (glyph_extents == null) - glyph_extents = new List(); return (IEnumerable)glyph_extents; } } public int Count { - get { return (GlyphExtents as List).Count; } + get { return glyph_extents.Count; } + } + + public TextExtents Clone() + { + TextExtents extents = new TextExtents(); + extents.glyph_extents.AddRange(GlyphExtents); + extents.BoundingBox = BoundingBox; + return extents; } #endregion @@ -95,18 +91,26 @@ namespace OpenTK.Graphics.Text internal void Add(RectangleF glyphExtent) { - (GlyphExtents as List).Add(glyphExtent); + glyph_extents.Add(glyphExtent); } internal void AddRange(IEnumerable glyphExtents) { - (GlyphExtents as List).AddRange(glyphExtents); + glyph_extents.AddRange(glyphExtents); } internal void Clear() { BoundingBox = RectangleF.Empty; - (GlyphExtents as List).Clear(); + glyph_extents.Clear(); + } + + #endregion + + #region IDisposable Members + + public virtual void Dispose() + { } #endregion diff --git a/Source/Utilities/IPoolable.cs b/Source/Utilities/IPoolable.cs new file mode 100644 index 00000000..68d83f36 --- /dev/null +++ b/Source/Utilities/IPoolable.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + interface IPoolable : IDisposable + { + void OnAcquire(); + void OnRelease(); + } + + interface IPoolable : IPoolable where T : IPoolable, new() + { + ObjectPool Owner { get; set; } + } +} diff --git a/Source/Utilities/ObjectPool.cs b/Source/Utilities/ObjectPool.cs new file mode 100644 index 00000000..3ad38112 --- /dev/null +++ b/Source/Utilities/ObjectPool.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + class ObjectPool where T : IPoolable, new() + { + Queue pool = new Queue(); + + public ObjectPool() + { } + + public T Acquire() + { + T item; + + if (pool.Count > 0) + { + item = pool.Dequeue(); + item.OnAcquire(); + } + else + { + item = new T(); + item.Owner = this; + item.OnAcquire(); + } + + return item; + } + + public void Release(T item) + { + if (item == null) + throw new ArgumentNullException("item"); + + item.OnRelease(); + pool.Enqueue(item); + } + } +} From a5c733774ad29e9e549431ea7ef5e6fd73937504 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Wed, 26 Nov 2008 16:35:19 +0000 Subject: [PATCH 28/53] UI should update when changing fonts. --- Source/Examples/WinForms/FontRendering.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Examples/WinForms/FontRendering.cs b/Source/Examples/WinForms/FontRendering.cs index 1d18a438..4427d611 100644 --- a/Source/Examples/WinForms/FontRendering.cs +++ b/Source/Examples/WinForms/FontRendering.cs @@ -50,6 +50,7 @@ namespace Examples.WinForms private void glControl1_Load(object sender, EventArgs e) { + glControl1.MakeCurrent(); GL.ClearColor(Color.SteelBlue); } @@ -58,10 +59,10 @@ namespace Examples.WinForms if (fontDialog.ShowDialog() == DialogResult.OK) { UpdateFontList(fontDialog.Font); + glControl1.Invalidate(); } } - private void textBox1_TextChanged(object sender, EventArgs e) { glControl1.Invalidate(); @@ -69,6 +70,7 @@ namespace Examples.WinForms private void glControl1_Paint(object sender, PaintEventArgs e) { + glControl1.MakeCurrent(); GL.Clear(ClearBufferMask.ColorBufferBit); GL.Color3(Color.White); @@ -87,6 +89,8 @@ namespace Examples.WinForms private void glControl1_Resize(object sender, EventArgs e) { + glControl1.MakeCurrent(); + if (glControl1.ClientSize.Height == 0) glControl1.ClientSize = new System.Drawing.Size(glControl1.ClientSize.Width, 1); From baf3247afe92b04e405f893184fc320242cafdc1 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Wed, 26 Nov 2008 21:49:05 +0000 Subject: [PATCH 29/53] Initial work on new interface. Use subpixel antialiasing. --- Source/Examples/OpenGL/FrameBufferObject.cs | 2 +- Source/Examples/OpenGL/JuliaSetFractal.cs | 3 +- Source/Examples/Tests/GameWindowStates.cs | 9 ++-- Source/Examples/Tutorial/Fonts.cs | 4 +- Source/Examples/Tutorial/Text.cs | 7 +-- .../WinForms/FontRendering.Designer.cs | 2 + Source/Examples/WinForms/FontRendering.cs | 9 ++-- Source/Examples/WinForms/W01_First_Window.cs | 2 + Source/Utilities/Graphics/AlphaTexture2D.cs | 8 ---- Source/Utilities/Graphics/ITextPrinter.cs | 10 ++--- Source/Utilities/Graphics/RgbaTexture2D.cs | 18 ++++++++ .../Graphics/Text/GL1TextOutputProvider.cs | 4 +- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 43 +++++++++++-------- Source/Utilities/Graphics/Text/GlyphSheet.cs | 14 +++--- .../Graphics/Text/IGlyphRasterizer.cs | 2 +- .../Graphics/Text/ITextOutputProvider.cs | 3 +- Source/Utilities/Graphics/Text/TextBlock.cs | 10 ++--- Source/Utilities/Graphics/TextPrinter.cs | 40 +++++++++-------- 18 files changed, 107 insertions(+), 83 deletions(-) create mode 100644 Source/Utilities/Graphics/RgbaTexture2D.cs diff --git a/Source/Examples/OpenGL/FrameBufferObject.cs b/Source/Examples/OpenGL/FrameBufferObject.cs index b87e5a7b..c8c38e0e 100644 --- a/Source/Examples/OpenGL/FrameBufferObject.cs +++ b/Source/Examples/OpenGL/FrameBufferObject.cs @@ -237,7 +237,7 @@ namespace Examples.Tutorial GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); text.Begin(); - text.Print((1.0 / e.Time).ToString("F2"), sans); + text.Print((1.0 / e.Time).ToString("F2"), sans, Color.White); text.End(); GL.PushMatrix(); diff --git a/Source/Examples/OpenGL/JuliaSetFractal.cs b/Source/Examples/OpenGL/JuliaSetFractal.cs index 08442e24..df5658a0 100644 --- a/Source/Examples/OpenGL/JuliaSetFractal.cs +++ b/Source/Examples/OpenGL/JuliaSetFractal.cs @@ -289,8 +289,7 @@ namespace Examples.Tutorial // Then, render the fps: GL.UseProgram(0); printer.Begin(); - GL.Color3(Color.PaleGoldenrod); - printer.Print((1 / e.Time).ToString("F2"), font, TextPrinterOptions.NoCache); + printer.Print((1 / e.Time).ToString("F2"), font, Color.PaleGoldenrod, RectangleF .Empty, TextPrinterOptions.NoCache); printer.End(); SwapBuffers(); diff --git a/Source/Examples/Tests/GameWindowStates.cs b/Source/Examples/Tests/GameWindowStates.cs index 4ef3761c..862989c3 100644 --- a/Source/Examples/Tests/GameWindowStates.cs +++ b/Source/Examples/Tests/GameWindowStates.cs @@ -118,13 +118,12 @@ namespace Examples.Tests printer.Begin(); - printer.Print("Instructions:", font); GL.Translate(0, font.Height, 0); - printer.Print(String.Format("1 - cycle through window styles (current: {0}).", this.WindowState), font); - GL.Translate(0, font.Height, 0); - printer.Print(String.Format("2 - cycle through window borders (current: {0}).", this.WindowBorder), font); + printer.Print("Instructions:", font, Color.White); + printer.Print(String.Format("1 - cycle through window styles (current: {0}).", this.WindowState), font, Color.White, new RectangleF(0, font.Height, 0, 0)); + printer.Print(String.Format("2 - cycle through window borders (current: {0}).", this.WindowBorder), font, Color.White, new RectangleF(0, 2 * font.Height, 0, 0)); GL.Translate(0, font.Height, 0); printer.Print(String.Format("3 - toggle fullscreen (current: {0}).", - this.WindowState == WindowState.Fullscreen ? "enabled" : "disabled"), font); + this.WindowState == WindowState.Fullscreen ? "enabled" : "disabled"), font, Color.White, new RectangleF(0, 2 * font.Height, 0, 0)); printer.End(); diff --git a/Source/Examples/Tutorial/Fonts.cs b/Source/Examples/Tutorial/Fonts.cs index 3973c3fe..e675012d 100644 --- a/Source/Examples/Tutorial/Fonts.cs +++ b/Source/Examples/Tutorial/Fonts.cs @@ -162,7 +162,7 @@ namespace Examples.Tutorial // Print using the first font. for (int i = 0; i < fonts.Length / 2; i++) { - printer.Print(text, fonts[i]); + printer.Print(text, fonts[i], Color.White); GL.Translate(0, fonts[i].Height, 0); } @@ -174,7 +174,7 @@ namespace Examples.Tutorial GL.Translate(rect.Width + 32.0f, 0, 0); for (int i = fonts.Length / 2; i < fonts.Length; i++) { - printer.Print(text, fonts[i]); + printer.Print(text, fonts[i], Color.White); GL.Translate(0, fonts[i].Height, 0); } diff --git a/Source/Examples/Tutorial/Text.cs b/Source/Examples/Tutorial/Text.cs index fa2dcf72..08a198e4 100644 --- a/Source/Examples/Tutorial/Text.cs +++ b/Source/Examples/Tutorial/Text.cs @@ -129,13 +129,10 @@ namespace Examples.Tutorial // Print FPS counter. Since the counter changes per frame, // it shouldn't be cached (TextPrinterOptions.NoCache). - GL.Color3(Color.LightYellow); - text.Print((1.0 / e.Time).ToString("F2"), sans, TextPrinterOptions.NoCache); + text.Print((1.0 / e.Time).ToString("F2"), sans, Color.LightYellow, RectangleF.Empty, TextPrinterOptions.NoCache); // Print the actual text. - GL.Translate(0.0f, current_position, 0.0f); - GL.Color3(Color.White); - text.Print(poem, serif); + text.Print(poem, serif, Color.White, new RectangleF(0, current_position, 0, 0), TextPrinterOptions.Default); text.End(); diff --git a/Source/Examples/WinForms/FontRendering.Designer.cs b/Source/Examples/WinForms/FontRendering.Designer.cs index c0b43c16..c8a6f324 100644 --- a/Source/Examples/WinForms/FontRendering.Designer.cs +++ b/Source/Examples/WinForms/FontRendering.Designer.cs @@ -62,6 +62,8 @@ // // textBox1 // + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.textBox1.Location = new System.Drawing.Point(12, 11); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(550, 22); diff --git a/Source/Examples/WinForms/FontRendering.cs b/Source/Examples/WinForms/FontRendering.cs index 4427d611..aa98f9f1 100644 --- a/Source/Examples/WinForms/FontRendering.cs +++ b/Source/Examples/WinForms/FontRendering.cs @@ -14,7 +14,7 @@ namespace Examples.WinForms { #region Fields - float[] sizes = new float[] { 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 48 }; + float[] sizes = new float[] { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 28, 32, 36, 42, 48 }; List fonts = new List(); TextPrinter text = new TextPrinter(); @@ -70,15 +70,18 @@ namespace Examples.WinForms private void glControl1_Paint(object sender, PaintEventArgs e) { + GL.ClearColor(Color.Red); glControl1.MakeCurrent(); + //GL.ClearColor(Color.Gainsboro); GL.Clear(ClearBufferMask.ColorBufferBit); - GL.Color3(Color.White); + //GL.Color4(Color.Blue); + //GL.BlendColor(0, 0, 0, 0); text.Begin(); foreach (Font font in fonts) { - text.Print(textBox1.Text, font); + text.Print(textBox1.Text, font, Color.White); GL.Translate(0, font.Height, 0); } diff --git a/Source/Examples/WinForms/W01_First_Window.cs b/Source/Examples/WinForms/W01_First_Window.cs index 022192d2..e4d545b8 100644 --- a/Source/Examples/WinForms/W01_First_Window.cs +++ b/Source/Examples/WinForms/W01_First_Window.cs @@ -59,6 +59,8 @@ namespace Examples.WinForms private void glControl1_Paint(object sender, PaintEventArgs e) { + glControl1.MakeCurrent(); + GL.Clear(ClearBufferMask.ColorBufferBit); glControl1.SwapBuffers(); } diff --git a/Source/Utilities/Graphics/AlphaTexture2D.cs b/Source/Utilities/Graphics/AlphaTexture2D.cs index 637e4ec5..959f75cd 100644 --- a/Source/Utilities/Graphics/AlphaTexture2D.cs +++ b/Source/Utilities/Graphics/AlphaTexture2D.cs @@ -38,10 +38,6 @@ namespace OpenTK.Graphics /// class AlphaTexture2D : Texture2D { - #region Fields - - #endregion - #region Constructors /// @@ -53,10 +49,6 @@ namespace OpenTK.Graphics #endregion - #region Public Members - - #endregion - #region Protected Members protected override PixelInternalFormat InternalFormat diff --git a/Source/Utilities/Graphics/ITextPrinter.cs b/Source/Utilities/Graphics/ITextPrinter.cs index 717b2870..f9c3dc22 100644 --- a/Source/Utilities/Graphics/ITextPrinter.cs +++ b/Source/Utilities/Graphics/ITextPrinter.cs @@ -19,12 +19,12 @@ namespace OpenTK.Graphics { void Begin(); void End(); - void Print(string text, Font font); - void Print(string text, Font font, TextPrinterOptions options); - void Print(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle); + void Print(string text, Font font, Color color); + void Print(string text, Font font, Color color, RectangleF layoutRectangle); + void Print(string text, Font font, Color color, RectangleF layoutRectangle, TextPrinterOptions options); TextExtents Measure(string text, Font font); - TextExtents Measure(string text, Font font, TextPrinterOptions options); - TextExtents Measure(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle); + TextExtents Measure(string text, Font font, RectangleF layoutRectangle); + TextExtents Measure(string text, Font font, RectangleF layoutRectangle, TextPrinterOptions options); [Obsolete("Use TextPrinter.Print instead")] void Draw(TextHandle handle); diff --git a/Source/Utilities/Graphics/RgbaTexture2D.cs b/Source/Utilities/Graphics/RgbaTexture2D.cs new file mode 100644 index 00000000..7959ac65 --- /dev/null +++ b/Source/Utilities/Graphics/RgbaTexture2D.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics +{ + class RgbaTexture2D : Texture2D + { + public RgbaTexture2D(int width, int height) + : base(width, height) + { } + + protected override PixelInternalFormat InternalFormat + { + get { return PixelInternalFormat.CompressedRgba; } + } + } +} diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index c75dbe9e..d7428830 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -55,9 +55,9 @@ namespace OpenTK.Graphics.Text #region ITextOutputProvider Members - public void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache) + public void Print(TextBlock block, PointF location, Color color, IGlyphRasterizer rasterizer, GlyphCache cache) { - using (TextExtents extents = rasterizer.MeasureText(block)) + using (TextExtents extents = rasterizer.MeasureText(block, location)) { //GL.BindTexture(TextureTarget.Texture2D, 2); diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index e1f722c9..e3f8ac11 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -79,7 +79,11 @@ namespace OpenTK.Graphics.Text public Bitmap Rasterize(Glyph glyph) { - RectangleF r = MeasureText(new TextBlock(glyph.Character.ToString(), glyph.Font, TextPrinterOptions.NoCache, RectangleF.Empty)).BoundingBox; + RectangleF r = MeasureText( + new TextBlock( + glyph.Character.ToString(), glyph.Font, + TextPrinterOptions.NoCache, SizeF.Empty), + PointF.Empty).BoundingBox; EnsureSurfaceSize(ref glyph_surface, ref glyph_renderer, glyph.Font); @@ -102,9 +106,15 @@ namespace OpenTK.Graphics.Text { SetTextRenderingOptions(gfx, glyph.Font); - gfx.Clear(Color.Transparent); - gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, - glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format); + //gfx.Clear(Color.Transparent); + //gfx.Clear(Color.FromArgb(255, 0, 0, 0)); + //gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, + // glyph.Font.Style & FontStyle.Italic != 0 ? load_glyph_string_format : default_string_format); + System.Windows.Forms.TextRenderer.DrawText(gfx, glyph.Character.ToString(), glyph.Font, Point.Empty, Color.White); + //, + // (glyph.Font.Style & FontStyle.Italic) != 0 ? + // System.Windows.Forms.TextFormatFlags.GlyphOverhangPadding : + // System.Windows.Forms.TextFormatFlags.Default); rect = FindEdges(bmp); } } @@ -113,7 +123,7 @@ namespace OpenTK.Graphics.Text #region MeasureText - public TextExtents MeasureText(TextBlock block) + public TextExtents MeasureText(TextBlock block, PointF location) { // First, check if we have cached this text block. Do not use block_cache.TryGetValue, to avoid thrashing // the user's TextBlockExtents struct. @@ -121,7 +131,8 @@ namespace OpenTK.Graphics.Text return block_cache[block]; // If this block is not cached, we have to measure it and (potentially) place it in the cache. - TextExtents extents = MeasureTextExtents(block); + TextExtents extents = MeasureTextExtents(block, location); + if ((block.Options & TextPrinterOptions.NoCache) == 0) block_cache.Add(block, extents); @@ -158,29 +169,25 @@ namespace OpenTK.Graphics.Text void SetTextRenderingOptions(System.Drawing.Graphics gfx, Font font) { // Small sizes look blurry without gridfitting, so turn that on. - if (font.Size <= 18.0f) - gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; - else - gfx.TextRenderingHint = TextRenderingHint.AntiAlias; + //if (font.Size <= 18.0f) + // gfx.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; + //else + gfx.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; + //gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; } #endregion #region MeasureTextExtents - TextExtents MeasureTextExtents(TextBlock block) + TextExtents MeasureTextExtents(TextBlock block, PointF location) { // Todo: Parse layout options: StringFormat format = default_string_format; - //if (block.Font.Style != FontStyle.Regular) - // format = load_glyph_string_format; - //else - // format = default_string_format; TextExtents extents = text_extents_pool.Acquire(); - PointF origin = PointF.Empty; - SizeF size = SizeF.Empty; + RectangleF rect = new RectangleF(location, block.Bounds); SetTextRenderingOptions(graphics, block.Font); @@ -203,7 +210,7 @@ namespace OpenTK.Graphics.Text { extents.AddRange(MeasureGlyphExtents( s, height, 0, s.Length, - block.LayoutRectangle, + rect, native_graphics, native_font, native_string_format)); height += block.Font.Height; } diff --git a/Source/Utilities/Graphics/Text/GlyphSheet.cs b/Source/Utilities/Graphics/Text/GlyphSheet.cs index b2fbbc5d..3b929437 100644 --- a/Source/Utilities/Graphics/Text/GlyphSheet.cs +++ b/Source/Utilities/Graphics/Text/GlyphSheet.cs @@ -36,27 +36,25 @@ namespace OpenTK.Graphics.Text { #region Fields - AlphaTexture2D texture; - GlyphPacker packer; + //AlphaTexture2D texture; + RgbaTexture2D texture = new RgbaTexture2D(512, 512); + GlyphPacker packer = new GlyphPacker(512, 512); #endregion #region Constructors public GlyphSheet() - { - Texture = new AlphaTexture2D(256, 256); - Packer = new GlyphPacker(256, 256); - } + { } #endregion #region Public Members - public AlphaTexture2D Texture + public Texture2D Texture { get { return texture; } - private set { texture = value; } + private set { texture = (RgbaTexture2D)value; } } public GlyphPacker Packer diff --git a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs index d07f7429..e52260c2 100644 --- a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs +++ b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs @@ -37,7 +37,7 @@ namespace OpenTK.Graphics.Text interface IGlyphRasterizer { Bitmap Rasterize(Glyph glyph); - TextExtents MeasureText(TextBlock block); + TextExtents MeasureText(TextBlock block, PointF location); void Rasterize(Glyph glyph, ref Bitmap bmp, out Rectangle rect); } } diff --git a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs index 095a5646..1f007932 100644 --- a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs @@ -28,11 +28,12 @@ using System; using System.Collections.Generic; using System.Text; +using System.Drawing; namespace OpenTK.Graphics.Text { interface ITextOutputProvider { - void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache); + void Print(TextBlock block, PointF location, Color color, IGlyphRasterizer rasterizer, GlyphCache cache); } } diff --git a/Source/Utilities/Graphics/Text/TextBlock.cs b/Source/Utilities/Graphics/Text/TextBlock.cs index 2c8df7e0..579acd11 100644 --- a/Source/Utilities/Graphics/Text/TextBlock.cs +++ b/Source/Utilities/Graphics/Text/TextBlock.cs @@ -41,7 +41,7 @@ namespace OpenTK.Graphics.Text public readonly Font Font; - public readonly RectangleF LayoutRectangle; + public readonly SizeF Bounds; public readonly TextPrinterOptions Options; @@ -51,11 +51,11 @@ namespace OpenTK.Graphics.Text #region Constructors - public TextBlock(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle) + public TextBlock(string text, Font font, TextPrinterOptions options, SizeF bounds) { Text = text; Font = font; - LayoutRectangle = layoutRectangle; + Bounds = bounds; Options = options; UsageCount = 0; } @@ -74,7 +74,7 @@ namespace OpenTK.Graphics.Text public override int GetHashCode() { - return Text.GetHashCode() ^ Font.GetHashCode() ^ LayoutRectangle.GetHashCode() ^ Options.GetHashCode(); + return Text.GetHashCode() ^ Font.GetHashCode() ^ Bounds.GetHashCode() ^ Options.GetHashCode(); } public Glyph this[int i] @@ -91,7 +91,7 @@ namespace OpenTK.Graphics.Text return Text == other.Text && Font == other.Font && - LayoutRectangle == other.LayoutRectangle && + Bounds == other.Bounds && Options == other.Options; } diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index bdabe00b..22474c81 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -92,9 +92,15 @@ namespace OpenTK.Graphics GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit); + //GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); + + //GL.Enable(EnableCap.ColorMaterial); GL.Enable(EnableCap.Texture2D); GL.Enable(EnableCap.Blend); - GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); + //GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // For grayscale + GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcColor); // For subpixel + //GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); // For subpixel with color + GL.Disable(EnableCap.DepthTest); } @@ -121,17 +127,17 @@ namespace OpenTK.Graphics #region Print - public void Print(string text, Font font) + public void Print(string text, Font font, Color color) { - Print(text, font, 0, RectangleF.Empty); + Print(text, font, color, RectangleF.Empty, TextPrinterOptions.Default); } - public void Print(string text, Font font, TextPrinterOptions options) + public void Print(string text, Font font, Color color, RectangleF layoutRectangle) { - Print(text, font, options, RectangleF.Empty); + Print(text, font, color, layoutRectangle, TextPrinterOptions.Default); } - public void Print(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle) + public void Print(string text, Font font, Color color, RectangleF layoutRectangle, TextPrinterOptions options) { if (String.IsNullOrEmpty(text)) return; @@ -139,7 +145,7 @@ namespace OpenTK.Graphics if (font == null) throw new ArgumentNullException("font"); - text_output.Print(new TextBlock(text, font, options, layoutRectangle), glyph_rasterizer, glyph_cache); + text_output.Print(new TextBlock(text, font, options, layoutRectangle.Size), layoutRectangle.Location, color, glyph_rasterizer, glyph_cache); } #endregion @@ -148,17 +154,17 @@ namespace OpenTK.Graphics public TextExtents Measure(string text, Font font) { - return Measure(text, font, 0, RectangleF.Empty); - } - - public TextExtents Measure(string text, Font font, TextPrinterOptions options) - { - return Measure(text, font, options, RectangleF.Empty); + return Measure(text, font, RectangleF.Empty, TextPrinterOptions.Default); } - public TextExtents Measure(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle) + public TextExtents Measure(string text, Font font, RectangleF layoutRectangle) { - return glyph_rasterizer.MeasureText(new TextBlock(text, font, options, layoutRectangle)); + return Measure(text, font, layoutRectangle, TextPrinterOptions.Default); + } + + public TextExtents Measure(string text, Font font, RectangleF layoutRectangle, TextPrinterOptions options) + { + return glyph_rasterizer.MeasureText(new TextBlock(text, font, options, layoutRectangle.Size), layoutRectangle.Location); } #endregion @@ -168,13 +174,13 @@ namespace OpenTK.Graphics [Obsolete("Use TextPrinter.Print instead")] public void Draw(TextHandle handle) { - Print(handle.Text, handle.GdiPFont); + Print(handle.Text, handle.GdiPFont, Color.White); } [Obsolete("Use TextPrinter.Print instead")] public void Draw(string text, TextureFont font) { - Print(text, font.font); + Print(text, font.font, Color.White); } [Obsolete("Use TextPrinter.Print instead")] From 73cb7a5dd27fe2929d95ac0827e89234874de9e8 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Wed, 26 Nov 2008 21:54:35 +0000 Subject: [PATCH 30/53] Add SuppressUnmanagedCodeSecurity and SetLastError attributes. --- Source/OpenTK/Platform/Windows/API.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/API.cs b/Source/OpenTK/Platform/Windows/API.cs index d55282d0..9a89dbd0 100644 --- a/Source/OpenTK/Platform/Windows/API.cs +++ b/Source/OpenTK/Platform/Windows/API.cs @@ -470,11 +470,8 @@ namespace OpenTK.Platform.Windows #region SwapBuffers - /// - /// - /// - /// - [DllImport("gdi32.dll")] + [SuppressUnmanagedCodeSecurity] + [DllImport("gdi32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SwapBuffers(IntPtr dc); @@ -1433,8 +1430,8 @@ namespace OpenTK.Platform.Windows #endregion #region PixelFormatDescriptor - - #pragma warning disable 0169 + + #pragma warning disable 0169 /// /// Describes a pixel format. It is used when interfacing with the WINAPI to create a new Context. @@ -1469,8 +1466,8 @@ namespace OpenTK.Platform.Windows internal int LayerMask; internal int VisibleMask; internal int DamageMask; - } - + } + #pragma warning restore 0169 #endregion From d9eeb2bd908771920b618225b17db6a8e40ae150 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Wed, 26 Nov 2008 21:55:43 +0000 Subject: [PATCH 31/53] Add debug output to SwapBuffers. --- Source/OpenTK/Platform/Windows/WinGLContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index c08cda77..b0323fd2 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -138,8 +138,8 @@ namespace OpenTK.Platform.Windows public void SwapBuffers() { - - Functions.SwapBuffers(currentWindow.DeviceContext); + if (!Functions.SwapBuffers(currentWindow.DeviceContext)) + Debug.Print("SwapBuffers failed, error: {0}", Marshal.GetLastWin32Error()); } #endregion From 92d590771307d4e15e1952f497dd5e62b221aa33 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 27 Nov 2008 12:04:26 +0000 Subject: [PATCH 32/53] Build examples last, because prebuild/nant can't automatically resolve dependencies. --- Build/Prebuild.xml | 70 +++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Build/Prebuild.xml b/Build/Prebuild.xml index 6834ea60..d8e056f4 100644 --- a/Build/Prebuild.xml +++ b/Build/Prebuild.xml @@ -31,40 +31,6 @@ Prebuild.xml - - - - - ../../Binaries/Debug/Examples - true - - - - - - ../../Binaries/Release/Examples - true - - - - - - - - - - - - - - - - - - - - - @@ -166,7 +132,41 @@ - + + + + + + ../../Binaries/Debug/Examples + true + + + + + + ../../Binaries/Release/Examples + true + + + + + + + + + + + + + + + + + + + + + From 79c7f64f7f7c1ab543ee71d8dd60c180535bb27f Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 27 Nov 2008 12:14:12 +0000 Subject: [PATCH 33/53] RgbaTexture2D should not be compressed. --- Source/Utilities/Graphics/RgbaTexture2D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Utilities/Graphics/RgbaTexture2D.cs b/Source/Utilities/Graphics/RgbaTexture2D.cs index 7959ac65..8aa70533 100644 --- a/Source/Utilities/Graphics/RgbaTexture2D.cs +++ b/Source/Utilities/Graphics/RgbaTexture2D.cs @@ -12,7 +12,7 @@ namespace OpenTK.Graphics protected override PixelInternalFormat InternalFormat { - get { return PixelInternalFormat.CompressedRgba; } + get { return PixelInternalFormat.Rgba; } } } } From 6e5056e7aaaf9a6567b5cd0423fcd6485c5473ec Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 27 Nov 2008 12:16:41 +0000 Subject: [PATCH 34/53] GDI+ bitmaps are stored as Bgra, not Rgba. --- Source/Utilities/Graphics/Texture2D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Utilities/Graphics/Texture2D.cs b/Source/Utilities/Graphics/Texture2D.cs index 9be42a3d..53108fc8 100644 --- a/Source/Utilities/Graphics/Texture2D.cs +++ b/Source/Utilities/Graphics/Texture2D.cs @@ -136,7 +136,7 @@ namespace OpenTK.Graphics GL.TexSubImage2D(TextureTarget.Texture2D, mipLevel, target.Left, target.Top, target.Width, target.Height, - OpenTK.Graphics.PixelFormat.Rgba, + OpenTK.Graphics.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0); } finally From 52577946e351c8f42403451020556c244388b26b Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 27 Nov 2008 16:37:48 +0000 Subject: [PATCH 35/53] Set compatible text rendering to false, in order to improve text rendering in the WinForms samples. --- Source/Examples/ExampleLauncher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Examples/ExampleLauncher.cs b/Source/Examples/ExampleLauncher.cs index 0efef5d9..ac92204e 100644 --- a/Source/Examples/ExampleLauncher.cs +++ b/Source/Examples/ExampleLauncher.cs @@ -246,7 +246,7 @@ namespace Examples //fileIO.Demand(); Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(true); + Application.SetCompatibleTextRenderingDefault(false); using (Form exampleLauncher = new ExampleLauncher()) { Application.Run(exampleLauncher); From 3dd42ada721fcbcabcf524bc29c85198493d95e1 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Fri, 28 Nov 2008 12:46:58 +0000 Subject: [PATCH 36/53] Add workaround for mono GDI+ MeasureCharacterRanges and empty layout rectangles. --- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index e3f8ac11..5588ab1d 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -27,14 +27,11 @@ using System; using System.Collections.Generic; -using System.Text; -using System.Drawing; -using System.Drawing.Text; - -using OpenTK.Graphics.Text; -using OpenTK.Platform; using System.Diagnostics; +using System.Drawing; using System.Drawing.Imaging; +using System.Drawing.Text; +using OpenTK.Platform; namespace OpenTK.Graphics.Text { @@ -59,6 +56,8 @@ namespace OpenTK.Graphics.Text static readonly char[] newline_characters = new char[] { '\n', '\r' }; + static readonly SizeF MaximumGraphicsClipSize; + #endregion #region Constructors @@ -66,6 +65,12 @@ namespace OpenTK.Graphics.Text static GdiPlusGlyphRasterizer() { default_string_format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; + + using (Bitmap bmp = new Bitmap(1, 1)) + using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp)) + { + MaximumGraphicsClipSize = gfx.ClipBounds.Size; + } } public GdiPlusGlyphRasterizer() @@ -79,11 +84,11 @@ namespace OpenTK.Graphics.Text public Bitmap Rasterize(Glyph glyph) { - RectangleF r = MeasureText( - new TextBlock( - glyph.Character.ToString(), glyph.Font, - TextPrinterOptions.NoCache, SizeF.Empty), - PointF.Empty).BoundingBox; + //RectangleF r = MeasureText( + // new TextBlock( + // glyph.Character.ToString(), glyph.Font, + // TextPrinterOptions.NoCache, SizeF.Empty), + // PointF.Empty).BoundingBox; EnsureSurfaceSize(ref glyph_surface, ref glyph_renderer, glyph.Font); @@ -183,11 +188,16 @@ namespace OpenTK.Graphics.Text TextExtents MeasureTextExtents(TextBlock block, PointF location) { // Todo: Parse layout options: + //StringFormat format = default_string_format; StringFormat format = default_string_format; TextExtents extents = text_extents_pool.Acquire(); RectangleF rect = new RectangleF(location, block.Bounds); + // Work around Mono/GDI+ bug, which causes incorrect + // text wraping when block.Bounds == SizeF.Empty. + if (block.Bounds == SizeF.Empty) + rect.Size = MaximumGraphicsClipSize; SetTextRenderingOptions(graphics, block.Font); @@ -209,8 +219,7 @@ namespace OpenTK.Graphics.Text foreach (string s in lines) { extents.AddRange(MeasureGlyphExtents( - s, height, 0, s.Length, - rect, + s, height, rect, native_graphics, native_font, native_string_format)); height += block.Font.Height; } @@ -227,27 +236,24 @@ namespace OpenTK.Graphics.Text // Gets the bounds of each character in a line of text. // The line is processed in blocks of 32 characters (GdiPlus.MaxMeasurableCharacterRanges). - IEnumerable MeasureGlyphExtents(string text, int height, int line_start, int line_length, + IEnumerable MeasureGlyphExtents(string text, int height, RectangleF layoutRect, IntPtr native_graphics, IntPtr native_font, IntPtr native_string_format) { - RectangleF rect = new RectangleF(); - int line_end = line_start + line_length; - while (line_start < line_end) + RectangleF rect = new RectangleF(); + int current = 0; + while (current < text.Length) { - //if (text[line_start] == '\n' || text[line_start] == '\r') - //{ - // line_start++; - // continue; - //} - - int num_characters = (line_end - line_start) > GdiPlus.MaxMeasurableCharacterRanges ? + int num_characters = (text.Length - current) > GdiPlus.MaxMeasurableCharacterRanges ? GdiPlus.MaxMeasurableCharacterRanges : - line_end - line_start; + text.Length - current; int status = 0; for (int i = 0; i < num_characters; i++) { - characterRanges[i] = new CharacterRange(line_start + i, 1); + if (text[current + i] == '\n' || text[current + i] == '\r') + throw new Exception(); + + characterRanges[i] = new CharacterRange(current + i, 1); IntPtr region; status = GdiPlus.CreateRegion(out region); @@ -274,7 +280,7 @@ namespace OpenTK.Graphics.Text yield return rect; } - line_start += num_characters; + current += num_characters; } } From 2abc0461b024868ed2a0b6938b0ba107be4424df Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Sat, 29 Nov 2008 17:45:43 +0000 Subject: [PATCH 37/53] Moved Begin/End to ITextOutputProvider. Fixed text location. --- .../Graphics/Text/GL1TextOutputProvider.cs | 82 ++++++++++++++----- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 6 +- .../Graphics/Text/ITextOutputProvider.cs | 2 + Source/Utilities/Graphics/TextPrinter.cs | 46 ++--------- 4 files changed, 73 insertions(+), 63 deletions(-) diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index d7428830..b1d4f876 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -25,11 +25,8 @@ // #endregion -using System; using System.Collections.Generic; -using System.Text; using System.Drawing; - using OpenTK.Math; namespace OpenTK.Graphics.Text @@ -41,6 +38,7 @@ namespace OpenTK.Graphics.Text // Triangle lists, sorted by texture. Dictionary> active_lists = new Dictionary>(); Queue> inactive_lists = new Queue>(); + float[] viewport = new float[4]; #endregion @@ -55,27 +53,12 @@ namespace OpenTK.Graphics.Text #region ITextOutputProvider Members + #region Print + public void Print(TextBlock block, PointF location, Color color, IGlyphRasterizer rasterizer, GlyphCache cache) { using (TextExtents extents = rasterizer.MeasureText(block, location)) { - //GL.BindTexture(TextureTarget.Texture2D, 2); - - //GL.Begin(BeginMode.Quads); - - //GL.TexCoord2(0, 0); - //GL.Vertex2(0, 0); - //GL.TexCoord2(1, 0); - //GL.Vertex2(256, 0); - //GL.TexCoord2(1, 1); - //GL.Vertex2(256, 256); - //GL.TexCoord2(0, 1); - //GL.Vertex2(0, 256); - - //GL.End(); - - //GL.Translate(0, 256, 0); - // Build layout int current = 0; foreach (Glyph glyph in block) @@ -124,6 +107,9 @@ namespace OpenTK.Graphics.Text List list = active_lists[key]; key.Bind(); + + GL.Translate(location.X, location.Y, 0); + GL.Begin(BeginMode.Triangles); for (int i = 0; i < list.Count; i += 2) @@ -146,5 +132,61 @@ namespace OpenTK.Graphics.Text } #endregion + + #region Begin + + public void Begin() + { + if (GraphicsContext.CurrentContext == null) + throw new GraphicsContextException("No GraphicsContext is current in the calling thread."); + + GL.GetFloat(GetPName.Viewport, viewport); + + // Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode, + // with size equal to the window (in pixels). + // While we could also render text in 3D mode, it would be very hard to get + // pixel-perfect precision. + GL.MatrixMode(MatrixMode.Projection); + GL.PushMatrix(); + GL.LoadIdentity(); + GL.Ortho(viewport[0], viewport[2], viewport[3], viewport[1], -1.0, 1.0); + + GL.MatrixMode(MatrixMode.Modelview); + GL.PushMatrix(); + GL.LoadIdentity(); + + GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit); + + //GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); + + //GL.Enable(EnableCap.ColorMaterial); + GL.Enable(EnableCap.Texture2D); + GL.Enable(EnableCap.Blend); + //GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // For grayscale + GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcColor); // For subpixel + //GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); // For subpixel with color + + + GL.Disable(EnableCap.DepthTest); + } + + #endregion + + #region End + + public void End() + { + GL.PopAttrib(); + + GL.MatrixMode(MatrixMode.Modelview); + GL.PopMatrix(); + + GL.MatrixMode(MatrixMode.Projection); + GL.PopMatrix(); + } + + #endregion + + #endregion } } diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index 5588ab1d..6f5878d5 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -136,7 +136,7 @@ namespace OpenTK.Graphics.Text return block_cache[block]; // If this block is not cached, we have to measure it and (potentially) place it in the cache. - TextExtents extents = MeasureTextExtents(block, location); + TextExtents extents = MeasureTextExtents(block); if ((block.Options & TextPrinterOptions.NoCache) == 0) block_cache.Add(block, extents); @@ -185,7 +185,7 @@ namespace OpenTK.Graphics.Text #region MeasureTextExtents - TextExtents MeasureTextExtents(TextBlock block, PointF location) + TextExtents MeasureTextExtents(TextBlock block) { // Todo: Parse layout options: //StringFormat format = default_string_format; @@ -193,7 +193,7 @@ namespace OpenTK.Graphics.Text TextExtents extents = text_extents_pool.Acquire(); - RectangleF rect = new RectangleF(location, block.Bounds); + RectangleF rect = new RectangleF(PointF.Empty, block.Bounds); // Work around Mono/GDI+ bug, which causes incorrect // text wraping when block.Bounds == SizeF.Empty. if (block.Bounds == SizeF.Empty) diff --git a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs index 1f007932..34a219d2 100644 --- a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs @@ -35,5 +35,7 @@ namespace OpenTK.Graphics.Text interface ITextOutputProvider { void Print(TextBlock block, PointF location, Color color, IGlyphRasterizer rasterizer, GlyphCache cache); + void Begin(); + void End(); } } diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index 22474c81..0e67a698 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -34,8 +34,6 @@ namespace OpenTK.Graphics IGlyphRasterizer glyph_rasterizer; ITextOutputProvider text_output; - float[] viewport = new float[4]; - #endregion #region Constructors @@ -70,39 +68,10 @@ namespace OpenTK.Graphics /// /// Sets up OpenGL state for drawing text. /// + [Obsolete] public void Begin() { - if (GraphicsContext.CurrentContext == null) - throw new GraphicsContextException("No GraphicsContext is current in the calling thread."); - - GL.GetFloat(GetPName.Viewport, viewport); - - // Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode, - // with size equal to the window (in pixels). - // While we could also render text in 3D mode, it would be very hard to get - // pixel-perfect precision. - GL.MatrixMode(MatrixMode.Projection); - GL.PushMatrix(); - GL.LoadIdentity(); - GL.Ortho(viewport[0], viewport[2], viewport[3], viewport[1], -1.0, 1.0); - - GL.MatrixMode(MatrixMode.Modelview); - GL.PushMatrix(); - GL.LoadIdentity(); - - GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit); - - //GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); - - //GL.Enable(EnableCap.ColorMaterial); - GL.Enable(EnableCap.Texture2D); - GL.Enable(EnableCap.Blend); - //GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // For grayscale - GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcColor); // For subpixel - //GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); // For subpixel with color - - - GL.Disable(EnableCap.DepthTest); + text_output.Begin(); } #endregion @@ -112,15 +81,10 @@ namespace OpenTK.Graphics /// /// Restores OpenGL state. /// + [Obsolete] public void End() { - GL.PopAttrib(); - - GL.MatrixMode(MatrixMode.Modelview); - GL.PopMatrix(); - - GL.MatrixMode(MatrixMode.Projection); - GL.PopMatrix(); + text_output.End(); } #endregion @@ -145,7 +109,9 @@ namespace OpenTK.Graphics if (font == null) throw new ArgumentNullException("font"); + text_output.Begin(); text_output.Print(new TextBlock(text, font, options, layoutRectangle.Size), layoutRectangle.Location, color, glyph_rasterizer, glyph_cache); + text_output.End(); } #endregion From 9f3919e0bed891818debc9f97156e3d00efedf25 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Sat, 29 Nov 2008 18:04:15 +0000 Subject: [PATCH 38/53] Break up Id property into distinct methods. --- Source/Utilities/Graphics/Texture2D.cs | 58 ++++++++++++++++---------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/Source/Utilities/Graphics/Texture2D.cs b/Source/Utilities/Graphics/Texture2D.cs index 53108fc8..fe24d3b8 100644 --- a/Source/Utilities/Graphics/Texture2D.cs +++ b/Source/Utilities/Graphics/Texture2D.cs @@ -116,7 +116,6 @@ namespace OpenTK.Graphics throw new ArgumentNullException("data"); GraphicsUnit unit = GraphicsUnit.Pixel; - if (!bitmap.GetBounds(ref unit).Contains(source)) throw new InvalidOperationException("The source Rectangle is larger than the Bitmap."); @@ -211,6 +210,40 @@ namespace OpenTK.Graphics #endregion + #region Private Members + + int CreateTexture(int width, int height) + { + int id = GL.GenTexture(); + if (id == 0) + throw new GraphicsResourceException(String.Format("Texture creation failed, (Error: {0})", GL.GetError())); + + GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat, Width, Height, 0, + OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); + + return id; + } + + void SetDefaultTextureParameters(int id) + { + // Ensure the texture is allocated. + GL.BindTexture(TextureTarget.Texture2D, id); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); + if (GL.SupportsExtension("Version12")) + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge); + } + else + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Clamp); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Clamp); + } + } + + #endregion + #region IGraphicsResource Members #region IGraphicsResource.Context @@ -230,27 +263,8 @@ namespace OpenTK.Graphics GraphicsContext.Assert(); context = GraphicsContext.CurrentContext; - id = GL.GenTexture(); - if (id == 0) - throw new GraphicsResourceException(String.Format("Texture creation failed, (Error: {0})", GL.GetError())); - - // Ensure the texture is allocated. - GL.BindTexture(TextureTarget.Texture2D, id); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); - if (GL.SupportsExtension("Version12")) - { - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge); - } - else - { - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Clamp); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Clamp); - } - - GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat, Width, Height, 0, - OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); + id = CreateTexture(Width, Height); + SetDefaultTextureParameters(id); } return id; From 3a2aa4ece6d6ecc00572bc05edd34c9199804615 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Sat, 29 Nov 2008 18:22:51 +0000 Subject: [PATCH 39/53] Set default texture parameters before allocating memory for the texture. --- Source/Utilities/Graphics/Texture2D.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Utilities/Graphics/Texture2D.cs b/Source/Utilities/Graphics/Texture2D.cs index fe24d3b8..9a167c96 100644 --- a/Source/Utilities/Graphics/Texture2D.cs +++ b/Source/Utilities/Graphics/Texture2D.cs @@ -218,6 +218,8 @@ namespace OpenTK.Graphics if (id == 0) throw new GraphicsResourceException(String.Format("Texture creation failed, (Error: {0})", GL.GetError())); + SetDefaultTextureParameters(id); + GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat, Width, Height, 0, OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); @@ -264,7 +266,6 @@ namespace OpenTK.Graphics context = GraphicsContext.CurrentContext; id = CreateTexture(Width, Height); - SetDefaultTextureParameters(id); } return id; From 7a7718a57cf1f5cb49a56d3ee2efcf4dd9d03c7c Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Fri, 19 Dec 2008 15:37:09 +0000 Subject: [PATCH 40/53] Use new API. Fix initial message to "The quick brown fox jumped over the lazy dog." --- Source/Examples/WinForms/FontRendering.Designer.cs | 2 +- Source/Examples/WinForms/FontRendering.cs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/Examples/WinForms/FontRendering.Designer.cs b/Source/Examples/WinForms/FontRendering.Designer.cs index c8a6f324..24bef8f1 100644 --- a/Source/Examples/WinForms/FontRendering.Designer.cs +++ b/Source/Examples/WinForms/FontRendering.Designer.cs @@ -68,7 +68,7 @@ this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(550, 22); this.textBox1.TabIndex = 2; - this.textBox1.Text = "The quick fox jumped over the lazy dogs. 0123456789"; + this.textBox1.Text = "The quick brown fox jumped over the lazy dogs. 0123456789"; this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged); // // FontRendering diff --git a/Source/Examples/WinForms/FontRendering.cs b/Source/Examples/WinForms/FontRendering.cs index aa98f9f1..07363c64 100644 --- a/Source/Examples/WinForms/FontRendering.cs +++ b/Source/Examples/WinForms/FontRendering.cs @@ -77,15 +77,16 @@ namespace Examples.WinForms //GL.Color4(Color.Blue); //GL.BlendColor(0, 0, 0, 0); - text.Begin(); + //text.Begin(); + RectangleF rect = new RectangleF(); foreach (Font font in fonts) { - text.Print(textBox1.Text, font, Color.White); - GL.Translate(0, font.Height, 0); + text.Print(textBox1.Text, font, Color.White, rect); + rect.Y += font.Height; } - text.End(); + //text.End(); glControl1.SwapBuffers(); } From 5dd73d813fe1b75d735714f91fde68efef077d22 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 00:00:56 +0000 Subject: [PATCH 41/53] Added license notice. --- Source/Utilities/Graphics/RgbaTexture2D.cs | 29 +++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Source/Utilities/Graphics/RgbaTexture2D.cs b/Source/Utilities/Graphics/RgbaTexture2D.cs index 8aa70533..8cc32c5a 100644 --- a/Source/Utilities/Graphics/RgbaTexture2D.cs +++ b/Source/Utilities/Graphics/RgbaTexture2D.cs @@ -1,4 +1,31 @@ -using System; +#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; From 5135a258284bbb8e82fe18c630af0b5ed922e98e Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 01:00:07 +0000 Subject: [PATCH 42/53] Add GL.BlendColor(System.Drawing.Color) overload. --- Source/OpenTK/Graphics/GL/GLHelper.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/OpenTK/Graphics/GL/GLHelper.cs b/Source/OpenTK/Graphics/GL/GLHelper.cs index 3ddb68bd..1276e704 100644 --- a/Source/OpenTK/Graphics/GL/GLHelper.cs +++ b/Source/OpenTK/Graphics/GL/GLHelper.cs @@ -659,6 +659,15 @@ namespace OpenTK.Graphics #endregion + #region public static void BlendColor() overloads + + public static void BlendColor(System.Drawing.Color color) + { + GL.BlendColor(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f); + } + + #endregion + #region --- Overloads for OpenTK.Math --- public static void Normal3(Vector3 normal) From 1502fc27b76997ffde312fb2a20ac0046b80ef5b Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 01:01:55 +0000 Subject: [PATCH 43/53] Deprecate TextPrinter.Begin()/End(). These are only left for backwards compatibility. New code should set the desired projection and modelview matrices manually. --- .../Graphics/Text/GL1TextOutputProvider.cs | 47 ++++++++++++------- Source/Utilities/Graphics/TextPrinter.cs | 4 +- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index b1d4f876..6ece3591 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -28,6 +28,7 @@ using System.Collections.Generic; using System.Drawing; using OpenTK.Math; +using System; namespace OpenTK.Graphics.Text { @@ -39,6 +40,7 @@ namespace OpenTK.Graphics.Text Dictionary> active_lists = new Dictionary>(); Queue> inactive_lists = new Queue>(); float[] viewport = new float[4]; + bool legacy_mode = false; #endregion @@ -57,6 +59,19 @@ namespace OpenTK.Graphics.Text public void Print(TextBlock block, PointF location, Color color, IGlyphRasterizer rasterizer, GlyphCache cache) { + GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.DepthBufferBit); + + GL.Enable(EnableCap.Texture2D); + GL.Enable(EnableCap.Blend); + GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); // For subpixel with color + + GL.Disable(EnableCap.DepthTest); + + //GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); + //GL.Enable(EnableCap.ColorMaterial); + //GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // For grayscale + //GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcColor); // For subpixel + using (TextExtents extents = rasterizer.MeasureText(block, location)) { // Build layout @@ -109,6 +124,11 @@ namespace OpenTK.Graphics.Text key.Bind(); GL.Translate(location.X, location.Y, 0); + if (!legacy_mode) + { + GL.Scale(2.0 / (viewport[2] - viewport[0]), -2.0 / (viewport[3] - viewport[1]), 1); + } + GL.BlendColor(color); GL.Begin(BeginMode.Triangles); @@ -129,16 +149,20 @@ namespace OpenTK.Graphics.Text } active_lists.Clear(); + + GL.PopAttrib(); } #endregion #region Begin + [Obsolete] public void Begin() { - if (GraphicsContext.CurrentContext == null) - throw new GraphicsContextException("No GraphicsContext is current in the calling thread."); + GraphicsContext.Assert(); + + legacy_mode = true; GL.GetFloat(GetPName.Viewport, viewport); @@ -154,29 +178,18 @@ namespace OpenTK.Graphics.Text GL.MatrixMode(MatrixMode.Modelview); GL.PushMatrix(); GL.LoadIdentity(); - - GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit); - - //GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); - - //GL.Enable(EnableCap.ColorMaterial); - GL.Enable(EnableCap.Texture2D); - GL.Enable(EnableCap.Blend); - //GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // For grayscale - GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcColor); // For subpixel - //GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); // For subpixel with color - - - GL.Disable(EnableCap.DepthTest); } #endregion #region End + [Obsolete] public void End() { - GL.PopAttrib(); + GraphicsContext.Assert(); + + legacy_mode = false; GL.MatrixMode(MatrixMode.Modelview); GL.PopMatrix(); diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index 0e67a698..133289ca 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -109,9 +109,9 @@ namespace OpenTK.Graphics if (font == null) throw new ArgumentNullException("font"); - text_output.Begin(); + //text_output.Begin(); text_output.Print(new TextBlock(text, font, options, layoutRectangle.Size), layoutRectangle.Location, color, glyph_rasterizer, glyph_cache); - text_output.End(); + //text_output.End(); } #endregion From e7e5e1453f5b4bd26db6d1106f439efddffb1772 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 16:27:24 +0000 Subject: [PATCH 44/53] Added GL1.1 and GL1.2 rendering codepaths. Added selectable TextQuality level. Updated all interfaces to support the above. --- Source/Utilities/Graphics/ITextPrinter.cs | 8 +- .../Graphics/Text/GL11TextOutputProvider.cs | 55 +++++++++ .../Graphics/Text/GL12TextOutputProvider.cs | 48 ++++++++ .../Graphics/Text/GL1TextOutputProvider.cs | 47 +++++--- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 90 ++++++++------- Source/Utilities/Graphics/Text/GlyphCache.cs | 45 +++++--- Source/Utilities/Graphics/Text/GlyphSheet.cs | 18 +-- Source/Utilities/Graphics/Text/IGlyphCache.cs | 2 +- .../Graphics/Text/IGlyphRasterizer.cs | 5 +- .../Graphics/Text/ITextOutputProvider.cs | 2 +- Source/Utilities/Graphics/Text/TextExtents.cs | 2 + Source/Utilities/Graphics/Text/TextQuality.cs | 14 +++ Source/Utilities/Graphics/TextPrinter.cs | 108 +++++++++++++----- 13 files changed, 324 insertions(+), 120 deletions(-) create mode 100644 Source/Utilities/Graphics/Text/GL11TextOutputProvider.cs create mode 100644 Source/Utilities/Graphics/Text/GL12TextOutputProvider.cs create mode 100644 Source/Utilities/Graphics/Text/TextQuality.cs diff --git a/Source/Utilities/Graphics/ITextPrinter.cs b/Source/Utilities/Graphics/ITextPrinter.cs index f9c3dc22..882e2e50 100644 --- a/Source/Utilities/Graphics/ITextPrinter.cs +++ b/Source/Utilities/Graphics/ITextPrinter.cs @@ -20,11 +20,11 @@ namespace OpenTK.Graphics void Begin(); void End(); void Print(string text, Font font, Color color); - void Print(string text, Font font, Color color, RectangleF layoutRectangle); - void Print(string text, Font font, Color color, RectangleF layoutRectangle, TextPrinterOptions options); + void Print(string text, Font font, Color color, SizeF size); + void Print(string text, Font font, Color color, SizeF size, TextPrinterOptions options); TextExtents Measure(string text, Font font); - TextExtents Measure(string text, Font font, RectangleF layoutRectangle); - TextExtents Measure(string text, Font font, RectangleF layoutRectangle, TextPrinterOptions options); + TextExtents Measure(string text, Font font, SizeF size); + TextExtents Measure(string text, Font font, SizeF size, TextPrinterOptions options); [Obsolete("Use TextPrinter.Print instead")] void Draw(TextHandle handle); diff --git a/Source/Utilities/Graphics/Text/GL11TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL11TextOutputProvider.cs new file mode 100644 index 00000000..412ad4d4 --- /dev/null +++ b/Source/Utilities/Graphics/Text/GL11TextOutputProvider.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics.Text +{ + sealed class GL11TextOutputProvider : GL1TextOutputProvider + { + #region Fields + + TextQuality quality; + GlyphCache cache; + + #endregion + + #region Constuctors + + public GL11TextOutputProvider(TextQuality quality) + { + if (quality == TextQuality.High || quality == TextQuality.Default) + this.quality = TextQuality.Medium; + else + this.quality = quality; + + cache = new GlyphCache(); + } + + #endregion + + #region Protected Members + + protected override void SetBlendFunction() + { + GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // For grayscale + } + + protected override void SetColor(Color color) + { + GL.Color4(color); + } + + protected override TextQuality TextQuality + { + get { return quality; } + } + + protected override GlyphCache Cache + { + get { return cache; } + } + + #endregion + } +} diff --git a/Source/Utilities/Graphics/Text/GL12TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL12TextOutputProvider.cs new file mode 100644 index 00000000..ba8575d2 --- /dev/null +++ b/Source/Utilities/Graphics/Text/GL12TextOutputProvider.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace OpenTK.Graphics.Text +{ + sealed class GL12TextOutputProvider : GL1TextOutputProvider + { + #region Fields + + TextQuality quality; + GlyphCache cache; + + #endregion + + #region Constuctors + + public GL12TextOutputProvider(TextQuality quality) + { + this.quality = quality; + + cache = new GlyphCache(); + } + + #endregion + + protected override void SetBlendFunction() + { + GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); // For subpixel with color + } + + protected override void SetColor(Color color) + { + GL.BlendColor(color); + } + + protected override TextQuality TextQuality + { + get { return quality; } + } + + protected override GlyphCache Cache + { + get { return cache; } + } + } +} diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index 6ece3591..f37877c7 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -32,7 +32,7 @@ using System; namespace OpenTK.Graphics.Text { - class GL1TextOutputProvider : ITextOutputProvider + abstract class GL1TextOutputProvider : ITextOutputProvider { #region Fields @@ -57,22 +57,17 @@ namespace OpenTK.Graphics.Text #region Print - public void Print(TextBlock block, PointF location, Color color, IGlyphRasterizer rasterizer, GlyphCache cache) + public void Print(TextBlock block, Color color, IGlyphRasterizer rasterizer) { GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.DepthBufferBit); GL.Enable(EnableCap.Texture2D); GL.Enable(EnableCap.Blend); - GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); // For subpixel with color + SetBlendFunction(); GL.Disable(EnableCap.DepthTest); - //GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); - //GL.Enable(EnableCap.ColorMaterial); - //GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // For grayscale - //GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcColor); // For subpixel - - using (TextExtents extents = rasterizer.MeasureText(block, location)) + using (TextExtents extents = rasterizer.MeasureText(block)) { // Build layout int current = 0; @@ -83,10 +78,10 @@ namespace OpenTK.Graphics.Text current++; continue; } - else if (!cache.Contains(glyph)) - cache.Add(glyph); + else if (!Cache.Contains(glyph)) + Cache.Add(glyph, rasterizer, TextQuality); - CachedGlyphInfo info = cache[glyph]; + 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). @@ -123,12 +118,12 @@ namespace OpenTK.Graphics.Text key.Bind(); - GL.Translate(location.X, location.Y, 0); if (!legacy_mode) { GL.Scale(2.0 / (viewport[2] - viewport[0]), -2.0 / (viewport[3] - viewport[1]), 1); } - GL.BlendColor(color); + + SetColor(color); GL.Begin(BeginMode.Triangles); @@ -201,5 +196,29 @@ namespace OpenTK.Graphics.Text #endregion #endregion + + #region Protected Members + + protected abstract void SetBlendFunction(); + + protected abstract void SetColor(Color color); + + protected abstract TextQuality TextQuality { get; } + + protected abstract GlyphCache Cache { get; } + + #endregion + + #region Static Members + + public static GL1TextOutputProvider Create(TextQuality quality) + { + if (!GL.SupportsFunction("BlendFunc") || quality == TextQuality.Low || quality == TextQuality.Medium) + return new GL11TextOutputProvider(quality); + else + return new GL12TextOutputProvider(quality); + } + + #endregion } } diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index 6f5878d5..19d31bc8 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -48,6 +48,8 @@ namespace OpenTK.Graphics.Text Bitmap glyph_surface; System.Drawing.Graphics glyph_renderer; + readonly List measured_glyphs = new List(256); + readonly ObjectPool text_extents_pool = new ObjectPool(); // Check the constructor, too, for additional flags. @@ -73,8 +75,7 @@ namespace OpenTK.Graphics.Text } } - public GdiPlusGlyphRasterizer() - { } + public GdiPlusGlyphRasterizer() { } #endregion @@ -84,15 +85,13 @@ namespace OpenTK.Graphics.Text public Bitmap Rasterize(Glyph glyph) { - //RectangleF r = MeasureText( - // new TextBlock( - // glyph.Character.ToString(), glyph.Font, - // TextPrinterOptions.NoCache, SizeF.Empty), - // PointF.Empty).BoundingBox; + return Rasterize(glyph, TextQuality.Default); + } + public Bitmap Rasterize(Glyph glyph, TextQuality quality) + { EnsureSurfaceSize(ref glyph_surface, ref glyph_renderer, glyph.Font); - - SetTextRenderingOptions(glyph_renderer, glyph.Font); + SetTextRenderingOptions(glyph_renderer, glyph.Font, quality); glyph_renderer.Clear(Color.Transparent); glyph_renderer.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, @@ -103,32 +102,16 @@ namespace OpenTK.Graphics.Text return glyph_surface.Clone(r2, System.Drawing.Imaging.PixelFormat.Format32bppArgb); } - public void Rasterize(Glyph glyph, ref Bitmap bmp, out Rectangle rect) - { - EnsureSurfaceSize(ref bmp, ref glyph_renderer, glyph.Font); - - using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp)) - { - SetTextRenderingOptions(gfx, glyph.Font); - - //gfx.Clear(Color.Transparent); - //gfx.Clear(Color.FromArgb(255, 0, 0, 0)); - //gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty, - // glyph.Font.Style & FontStyle.Italic != 0 ? load_glyph_string_format : default_string_format); - System.Windows.Forms.TextRenderer.DrawText(gfx, glyph.Character.ToString(), glyph.Font, Point.Empty, Color.White); - //, - // (glyph.Font.Style & FontStyle.Italic) != 0 ? - // System.Windows.Forms.TextFormatFlags.GlyphOverhangPadding : - // System.Windows.Forms.TextFormatFlags.Default); - rect = FindEdges(bmp); - } - } - #endregion #region MeasureText - public TextExtents MeasureText(TextBlock block, PointF location) + public TextExtents MeasureText(TextBlock block) + { + return MeasureText(block, TextQuality.Default); + } + + public TextExtents MeasureText(TextBlock block, TextQuality quality) { // First, check if we have cached this text block. Do not use block_cache.TryGetValue, to avoid thrashing // the user's TextBlockExtents struct. @@ -136,7 +119,7 @@ namespace OpenTK.Graphics.Text return block_cache[block]; // If this block is not cached, we have to measure it and (potentially) place it in the cache. - TextExtents extents = MeasureTextExtents(block); + TextExtents extents = MeasureTextExtents(block, quality); if ((block.Options & TextPrinterOptions.NoCache) == 0) block_cache.Add(block, extents); @@ -171,21 +154,39 @@ namespace OpenTK.Graphics.Text #region SetRenderingOptions // Modify rendering settings (antialiasing, grid fitting) to improve appearance. - void SetTextRenderingOptions(System.Drawing.Graphics gfx, Font font) + void SetTextRenderingOptions(System.Drawing.Graphics gfx, Font font, TextQuality quality) { - // Small sizes look blurry without gridfitting, so turn that on. - //if (font.Size <= 18.0f) - // gfx.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; - //else - gfx.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; - //gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + switch (quality) + { + case TextQuality.Default: + gfx.TextRenderingHint = TextRenderingHint.SystemDefault; + break; + + case TextQuality.High: + gfx.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; + break; + + case TextQuality.Medium: + if (font.Size <= 18.0f) + gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + else + gfx.TextRenderingHint = TextRenderingHint.AntiAlias; + break; + + case TextQuality.Low: + if (font.Size <= 18.0f) + gfx.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit; + else + gfx.TextRenderingHint = TextRenderingHint.SingleBitPerPixel; + break; + } } #endregion #region MeasureTextExtents - TextExtents MeasureTextExtents(TextBlock block) + TextExtents MeasureTextExtents(TextBlock block, TextQuality quality) { // Todo: Parse layout options: //StringFormat format = default_string_format; @@ -199,7 +200,7 @@ namespace OpenTK.Graphics.Text if (block.Bounds == SizeF.Empty) rect.Size = MaximumGraphicsClipSize; - SetTextRenderingOptions(graphics, block.Font); + SetTextRenderingOptions(graphics, block.Font, quality); IntPtr native_graphics = GdiPlus.GetNativeGraphics(graphics); IntPtr native_font = GdiPlus.GetNativeFont(block.Font); @@ -239,6 +240,8 @@ namespace OpenTK.Graphics.Text IEnumerable MeasureGlyphExtents(string text, int height, RectangleF layoutRect, IntPtr native_graphics, IntPtr native_font, IntPtr native_string_format) { + measured_glyphs.Clear(); + RectangleF rect = new RectangleF(); int current = 0; while (current < text.Length) @@ -277,11 +280,14 @@ namespace OpenTK.Graphics.Text rect.Y += height; - yield return rect; + //yield return rect; + measured_glyphs.Add(rect); } current += num_characters; } + + return measured_glyphs; } #endregion diff --git a/Source/Utilities/Graphics/Text/GlyphCache.cs b/Source/Utilities/Graphics/Text/GlyphCache.cs index fa99e041..090f9a9f 100644 --- a/Source/Utilities/Graphics/Text/GlyphCache.cs +++ b/Source/Utilities/Graphics/Text/GlyphCache.cs @@ -31,41 +31,54 @@ using System.Drawing; namespace OpenTK.Graphics.Text { - class GlyphCache : IGlyphCache + abstract class GlyphCache : IGlyphCache + { + #region IGlyphCache Members + + public abstract void Add(Glyph glyph, IGlyphRasterizer rasterizer, TextQuality quality); + + public abstract bool Contains(Glyph glyph); + + public abstract CachedGlyphInfo this[Glyph glyph] { get; } + + #endregion + } + + class GlyphCache : GlyphCache where T : Texture2D { #region Fields - IGlyphRasterizer rasterizer; - List sheets = new List(); + List> sheets = new List>(); Bitmap bmp = new Bitmap(32, 32); Dictionary cached_glyphs = new Dictionary(); + const int SheetWidth = 512, SheetHeight = 512; + #endregion #region Constructors - public GlyphCache(IGlyphRasterizer rasterizer) + public GlyphCache() { - if (rasterizer == null) - throw new ArgumentNullException("rasterizer"); - - this.rasterizer = rasterizer; - sheets.Add(new GlyphSheet()); + sheets.Add(new GlyphSheet(SheetWidth, SheetHeight)); } #endregion #region IGlyphCache Members - public void Add(Glyph glyph) + public override void Add(Glyph glyph, IGlyphRasterizer rasterizer, TextQuality quality) { + if (rasterizer == null) + throw new ArgumentNullException("rasterizer"); + bool inserted = false; - using (Bitmap bmp = rasterizer.Rasterize(glyph)) + using (Bitmap bmp = rasterizer.Rasterize(glyph, quality)) { Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); - foreach (GlyphSheet sheet in sheets) + foreach (GlyphSheet sheet in sheets) { inserted = InsertGlyph(glyph, bmp, rect, sheet); if (inserted) @@ -74,19 +87,19 @@ namespace OpenTK.Graphics.Text if (!inserted) { - GlyphSheet sheet = new GlyphSheet(); + GlyphSheet sheet = new GlyphSheet(SheetWidth, SheetHeight); sheets.Add(sheet); InsertGlyph(glyph, bmp, rect, sheet); } } } - public bool Contains(Glyph glyph) + public override bool Contains(Glyph glyph) { return cached_glyphs.ContainsKey(glyph); } - public CachedGlyphInfo this[Glyph glyph] + public override CachedGlyphInfo this[Glyph glyph] { get { @@ -99,7 +112,7 @@ namespace OpenTK.Graphics.Text #region Private Members // Asks the packer for an empty space and writes the glyph there. - bool InsertGlyph(Glyph glyph, Bitmap bmp, Rectangle source, GlyphSheet sheet) + bool InsertGlyph(Glyph glyph, Bitmap bmp, Rectangle source, GlyphSheet sheet) { Rectangle target = new Rectangle(); if (!sheet.Packer.TryAdd(source, out target)) diff --git a/Source/Utilities/Graphics/Text/GlyphSheet.cs b/Source/Utilities/Graphics/Text/GlyphSheet.cs index 3b929437..655638c4 100644 --- a/Source/Utilities/Graphics/Text/GlyphSheet.cs +++ b/Source/Utilities/Graphics/Text/GlyphSheet.cs @@ -32,35 +32,35 @@ using System.Drawing; namespace OpenTK.Graphics.Text { - class GlyphSheet + class GlyphSheet where T : Texture2D { #region Fields - //AlphaTexture2D texture; - RgbaTexture2D texture = new RgbaTexture2D(512, 512); - GlyphPacker packer = new GlyphPacker(512, 512); + readonly T texture; + readonly GlyphPacker packer; #endregion #region Constructors - public GlyphSheet() - { } + public GlyphSheet(int width, int height) + { + texture = (T)typeof(T).GetConstructor(new Type[] { typeof(int), typeof(int) }).Invoke(new object[] { width, height }); + packer = new GlyphPacker(width, height); + } #endregion #region Public Members - public Texture2D Texture + public T Texture { get { return texture; } - private set { texture = (RgbaTexture2D)value; } } public GlyphPacker Packer { get { return packer; } - private set { packer = value; } } #endregion diff --git a/Source/Utilities/Graphics/Text/IGlyphCache.cs b/Source/Utilities/Graphics/Text/IGlyphCache.cs index 49195888..d18a7dd7 100644 --- a/Source/Utilities/Graphics/Text/IGlyphCache.cs +++ b/Source/Utilities/Graphics/Text/IGlyphCache.cs @@ -29,7 +29,7 @@ namespace OpenTK.Graphics.Text { interface IGlyphCache { - void Add(Glyph glyph); + void Add(Glyph glyph, IGlyphRasterizer rasterizer, TextQuality quality); bool Contains(Glyph glyph); CachedGlyphInfo this[Glyph glyph] { get; } } diff --git a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs index e52260c2..e5d60594 100644 --- a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs +++ b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs @@ -37,7 +37,8 @@ namespace OpenTK.Graphics.Text interface IGlyphRasterizer { Bitmap Rasterize(Glyph glyph); - TextExtents MeasureText(TextBlock block, PointF location); - void Rasterize(Glyph glyph, ref Bitmap bmp, out Rectangle rect); + Bitmap Rasterize(Glyph glyph, TextQuality quality); + TextExtents MeasureText(TextBlock block); + TextExtents MeasureText(TextBlock block, TextQuality quality); } } diff --git a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs index 34a219d2..fe0902ef 100644 --- a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs @@ -34,7 +34,7 @@ namespace OpenTK.Graphics.Text { interface ITextOutputProvider { - void Print(TextBlock block, PointF location, Color color, IGlyphRasterizer rasterizer, GlyphCache cache); + void Print(TextBlock block, Color color, IGlyphRasterizer rasterizer); void Begin(); void End(); } diff --git a/Source/Utilities/Graphics/Text/TextExtents.cs b/Source/Utilities/Graphics/Text/TextExtents.cs index c8a241a7..03a923a2 100644 --- a/Source/Utilities/Graphics/Text/TextExtents.cs +++ b/Source/Utilities/Graphics/Text/TextExtents.cs @@ -40,6 +40,8 @@ namespace OpenTK.Graphics.Text protected RectangleF text_extents; protected List glyph_extents = new List(); + public static readonly TextExtents Empty = new TextExtents(); + #endregion #region Constructors diff --git a/Source/Utilities/Graphics/Text/TextQuality.cs b/Source/Utilities/Graphics/Text/TextQuality.cs new file mode 100644 index 00000000..7ed091f5 --- /dev/null +++ b/Source/Utilities/Graphics/Text/TextQuality.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics.Text +{ + public enum TextQuality + { + Default = 0, + Low, + Medium, + High + } +} diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index 133289ca..c285ec0e 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -30,9 +30,9 @@ namespace OpenTK.Graphics { #region Fields - GlyphCache glyph_cache; IGlyphRasterizer glyph_rasterizer; ITextOutputProvider text_output; + TextQuality text_quality; #endregion @@ -42,21 +42,16 @@ namespace OpenTK.Graphics /// Constructs a new TextPrinter object. /// public TextPrinter() - : this(null, null) + : this(null, null, TextQuality.Default) { } + + public TextPrinter(TextQuality quality) + : this(null, null, quality) { } + + TextPrinter(IGlyphRasterizer rasterizer, ITextOutputProvider output, TextQuality quality) { - } - - TextPrinter(IGlyphRasterizer rasterizer, ITextOutputProvider output/*, IGlyphCacheProvider, ITextOutputProvider */) - { - if (rasterizer == null) - rasterizer = new GdiPlusGlyphRasterizer(); - - if (output == null) - output = new GL1TextOutputProvider(); - glyph_rasterizer = rasterizer; - glyph_cache = new GlyphCache(rasterizer); text_output = output; + text_quality = quality; } #endregion @@ -71,7 +66,7 @@ namespace OpenTK.Graphics [Obsolete] public void Begin() { - text_output.Begin(); + TextOutput.Begin(); } #endregion @@ -84,7 +79,7 @@ namespace OpenTK.Graphics [Obsolete] public void End() { - text_output.End(); + TextOutput.End(); } #endregion @@ -93,25 +88,20 @@ namespace OpenTK.Graphics public void Print(string text, Font font, Color color) { - Print(text, font, color, RectangleF.Empty, TextPrinterOptions.Default); + Print(text, font, color, SizeF.Empty, TextPrinterOptions.Default); } - public void Print(string text, Font font, Color color, RectangleF layoutRectangle) + public void Print(string text, Font font, Color color, SizeF size) { - Print(text, font, color, layoutRectangle, TextPrinterOptions.Default); + Print(text, font, color, size, TextPrinterOptions.Default); } - public void Print(string text, Font font, Color color, RectangleF layoutRectangle, TextPrinterOptions options) + public void Print(string text, Font font, Color color, SizeF size, TextPrinterOptions options) { - if (String.IsNullOrEmpty(text)) + if (!ValidateParameters(text, font, size)) return; - if (font == null) - throw new ArgumentNullException("font"); - - //text_output.Begin(); - text_output.Print(new TextBlock(text, font, options, layoutRectangle.Size), layoutRectangle.Location, color, glyph_rasterizer, glyph_cache); - //text_output.End(); + text_output.Print(new TextBlock(text, font, options, size), color, Rasterizer); } #endregion @@ -120,17 +110,30 @@ namespace OpenTK.Graphics public TextExtents Measure(string text, Font font) { - return Measure(text, font, RectangleF.Empty, TextPrinterOptions.Default); + return Measure(text, font, SizeF.Empty, TextPrinterOptions.Default); } - public TextExtents Measure(string text, Font font, RectangleF layoutRectangle) + public TextExtents Measure(string text, Font font, SizeF size) { - return Measure(text, font, layoutRectangle, TextPrinterOptions.Default); + return Measure(text, font, size, TextPrinterOptions.Default); } - public TextExtents Measure(string text, Font font, RectangleF layoutRectangle, TextPrinterOptions options) + public TextExtents Measure(string text, Font font, SizeF size, TextPrinterOptions options) { - return glyph_rasterizer.MeasureText(new TextBlock(text, font, options, layoutRectangle.Size), layoutRectangle.Location); + if (!ValidateParameters(text, font, size)) + return TextExtents.Empty; + + return Rasterizer.MeasureText(new TextBlock(text, font, options, size)); + } + + #endregion + + #region Clear() + + public void Clear() + { + //glyph_cache.Clear(); + throw new NotImplementedException(); } #endregion @@ -158,5 +161,48 @@ namespace OpenTK.Graphics #endregion #endregion + + #region Private Members + + IGlyphRasterizer Rasterizer + { + get + { + if (glyph_rasterizer == null) + glyph_rasterizer = new GdiPlusGlyphRasterizer(); + + return glyph_rasterizer; + } + + } + + ITextOutputProvider TextOutput + { + get + { + if (text_output == null) + text_output = GL1TextOutputProvider.Create(text_quality); + + return text_output; + } + } + + #endregion + + #region Static Members + + static bool ValidateParameters(string text, Font font, SizeF size) + { + if (String.IsNullOrEmpty(text)) + return false; + if (font == null) + throw new ArgumentNullException("font"); + if (size.Width < 0 || size.Height < 0) + throw new ArgumentOutOfRangeException("size"); + + return true; + } + + #endregion } } From 64dfa91678b7d419f0eabeb9d9c8b202e4206d56 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 17:41:09 +0000 Subject: [PATCH 45/53] Added Clear() method to all classes that contain caches. Implemented IDisposable interface on the TextPrinter and all relevant classes. --- Source/Utilities/Graphics/ITextPrinter.cs | 2 +- .../Graphics/Text/GL1TextOutputProvider.cs | 72 +++++------- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 7 +- Source/Utilities/Graphics/Text/GlyphCache.cs | 28 ++++- Source/Utilities/Graphics/Text/GlyphSheet.cs | 21 +++- Source/Utilities/Graphics/Text/IGlyphCache.cs | 5 +- .../Graphics/Text/IGlyphRasterizer.cs | 1 + .../Graphics/Text/ITextOutputProvider.cs | 5 +- Source/Utilities/Graphics/TextPrinter.cs | 103 +++++++++++++----- 9 files changed, 161 insertions(+), 83 deletions(-) diff --git a/Source/Utilities/Graphics/ITextPrinter.cs b/Source/Utilities/Graphics/ITextPrinter.cs index 882e2e50..d8f3ca8e 100644 --- a/Source/Utilities/Graphics/ITextPrinter.cs +++ b/Source/Utilities/Graphics/ITextPrinter.cs @@ -15,7 +15,7 @@ namespace OpenTK.Graphics /// /// Defines the interface for a TextPrinter. /// - public interface ITextPrinter + public interface ITextPrinter : IDisposable { void Begin(); void End(); diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index f37877c7..c93177a2 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -39,8 +39,8 @@ namespace OpenTK.Graphics.Text // Triangle lists, sorted by texture. Dictionary> active_lists = new Dictionary>(); Queue> inactive_lists = new Queue>(); - float[] viewport = new float[4]; - bool legacy_mode = false; + + bool disposed; #endregion @@ -118,10 +118,12 @@ namespace OpenTK.Graphics.Text key.Bind(); - if (!legacy_mode) - { - GL.Scale(2.0 / (viewport[2] - viewport[0]), -2.0 / (viewport[3] - viewport[1]), 1); - } + //if (!legacy_mode) + //{ + // GL.PushMatrix(); + // GL.GetFloat(GetPName.Viewport, viewport); + // GL.Scale(2.0 / (viewport[2] - viewport[0]), -2.0 / (viewport[3] - viewport[1]), 1); + //} SetColor(color); @@ -134,6 +136,9 @@ namespace OpenTK.Graphics.Text } GL.End(); + + //if (!legacy_mode) + // GL.PopMatrix(); } // Clean layout @@ -150,47 +155,11 @@ namespace OpenTK.Graphics.Text #endregion - #region Begin + #region Clear - [Obsolete] - public void Begin() + public void Clear() { - GraphicsContext.Assert(); - - legacy_mode = true; - - GL.GetFloat(GetPName.Viewport, viewport); - - // Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode, - // with size equal to the window (in pixels). - // While we could also render text in 3D mode, it would be very hard to get - // pixel-perfect precision. - GL.MatrixMode(MatrixMode.Projection); - GL.PushMatrix(); - GL.LoadIdentity(); - GL.Ortho(viewport[0], viewport[2], viewport[3], viewport[1], -1.0, 1.0); - - GL.MatrixMode(MatrixMode.Modelview); - GL.PushMatrix(); - GL.LoadIdentity(); - } - - #endregion - - #region End - - [Obsolete] - public void End() - { - GraphicsContext.Assert(); - - legacy_mode = false; - - GL.MatrixMode(MatrixMode.Modelview); - GL.PopMatrix(); - - GL.MatrixMode(MatrixMode.Projection); - GL.PopMatrix(); + Cache.Clear(); } #endregion @@ -220,5 +189,18 @@ namespace OpenTK.Graphics.Text } #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!disposed) + { + Cache.Dispose(); + disposed = true; + } + } + + #endregion } } diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index 19d31bc8..80f16652 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -35,7 +35,7 @@ using OpenTK.Platform; namespace OpenTK.Graphics.Text { - class GdiPlusGlyphRasterizer : IGlyphRasterizer + sealed class GdiPlusGlyphRasterizer : IGlyphRasterizer { #region Fields @@ -129,6 +129,11 @@ namespace OpenTK.Graphics.Text #endregion + public void Clear() + { + block_cache.Clear(); + } + #endregion #region Private Members diff --git a/Source/Utilities/Graphics/Text/GlyphCache.cs b/Source/Utilities/Graphics/Text/GlyphCache.cs index 090f9a9f..9497d27c 100644 --- a/Source/Utilities/Graphics/Text/GlyphCache.cs +++ b/Source/Utilities/Graphics/Text/GlyphCache.cs @@ -41,10 +41,14 @@ namespace OpenTK.Graphics.Text public abstract CachedGlyphInfo this[Glyph glyph] { get; } + public abstract void Clear(); + + public abstract void Dispose(); + #endregion } - class GlyphCache : GlyphCache where T : Texture2D + sealed class GlyphCache : GlyphCache where T : Texture2D { #region Fields @@ -53,6 +57,8 @@ namespace OpenTK.Graphics.Text Dictionary cached_glyphs = new Dictionary(); + bool disposed; + const int SheetWidth = 512, SheetHeight = 512; #endregion @@ -106,6 +112,13 @@ namespace OpenTK.Graphics.Text return cached_glyphs[glyph]; } } + public override void Clear() + { + for (int i = 0; i < sheets.Count; i++) + sheets[i].Dispose(); + + sheets.Clear(); + } #endregion @@ -125,5 +138,18 @@ namespace OpenTK.Graphics.Text } #endregion + + #region IDisposable Members + + public override void Dispose() + { + if (!disposed) + { + Clear(); + disposed = true; + } + } + + #endregion } } diff --git a/Source/Utilities/Graphics/Text/GlyphSheet.cs b/Source/Utilities/Graphics/Text/GlyphSheet.cs index 655638c4..bc1cce1b 100644 --- a/Source/Utilities/Graphics/Text/GlyphSheet.cs +++ b/Source/Utilities/Graphics/Text/GlyphSheet.cs @@ -32,13 +32,15 @@ using System.Drawing; namespace OpenTK.Graphics.Text { - class GlyphSheet where T : Texture2D + class GlyphSheet : IDisposable where T : Texture2D { #region Fields readonly T texture; readonly GlyphPacker packer; + bool disposed; + #endregion #region Constructors @@ -46,7 +48,9 @@ namespace OpenTK.Graphics.Text public GlyphSheet(int width, int height) { texture = (T)typeof(T).GetConstructor(new Type[] { typeof(int), typeof(int) }).Invoke(new object[] { width, height }); - packer = new GlyphPacker(width, height); + //texture.MagnificationFilter = TextureMagFilter.Nearest; + //texture.MinificationFilter = TextureMinFilter.Nearest; + packer = new GlyphPacker(width, height); } #endregion @@ -64,5 +68,18 @@ namespace OpenTK.Graphics.Text } #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!disposed) + { + texture.Dispose(); + disposed = true; + } + } + + #endregion } } diff --git a/Source/Utilities/Graphics/Text/IGlyphCache.cs b/Source/Utilities/Graphics/Text/IGlyphCache.cs index d18a7dd7..fe5a60f6 100644 --- a/Source/Utilities/Graphics/Text/IGlyphCache.cs +++ b/Source/Utilities/Graphics/Text/IGlyphCache.cs @@ -25,12 +25,15 @@ // #endregion +using System; + namespace OpenTK.Graphics.Text { - interface IGlyphCache + interface IGlyphCache : IDisposable { void Add(Glyph glyph, IGlyphRasterizer rasterizer, TextQuality quality); bool Contains(Glyph glyph); CachedGlyphInfo this[Glyph glyph] { get; } + void Clear(); } } diff --git a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs index e5d60594..54e311e7 100644 --- a/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs +++ b/Source/Utilities/Graphics/Text/IGlyphRasterizer.cs @@ -40,5 +40,6 @@ namespace OpenTK.Graphics.Text Bitmap Rasterize(Glyph glyph, TextQuality quality); TextExtents MeasureText(TextBlock block); TextExtents MeasureText(TextBlock block, TextQuality quality); + void Clear(); } } diff --git a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs index fe0902ef..ce1aaf93 100644 --- a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs @@ -32,10 +32,9 @@ using System.Drawing; namespace OpenTK.Graphics.Text { - interface ITextOutputProvider + interface ITextOutputProvider : IDisposable { void Print(TextBlock block, Color color, IGlyphRasterizer rasterizer); - void Begin(); - void End(); + void Clear(); } } diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index c285ec0e..156d954b 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -34,6 +34,8 @@ namespace OpenTK.Graphics ITextOutputProvider text_output; TextQuality text_quality; + bool disposed; + #endregion #region Constructors @@ -58,32 +60,6 @@ namespace OpenTK.Graphics #region ITextPrinter Members - #region public void Begin() - - /// - /// Sets up OpenGL state for drawing text. - /// - [Obsolete] - public void Begin() - { - TextOutput.Begin(); - } - - #endregion - - #region public void End() - - /// - /// Restores OpenGL state. - /// - [Obsolete] - public void End() - { - TextOutput.End(); - } - - #endregion - #region Print public void Print(string text, Font font, Color color) @@ -98,10 +74,13 @@ namespace OpenTK.Graphics public void Print(string text, Font font, Color color, SizeF size, TextPrinterOptions options) { + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + if (!ValidateParameters(text, font, size)) return; - text_output.Print(new TextBlock(text, font, options, size), color, Rasterizer); + TextOutput.Print(new TextBlock(text, font, options, size), color, Rasterizer); } #endregion @@ -120,6 +99,9 @@ namespace OpenTK.Graphics public TextExtents Measure(string text, Font font, SizeF size, TextPrinterOptions options) { + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + if (!ValidateParameters(text, font, size)) return TextExtents.Empty; @@ -132,14 +114,64 @@ namespace OpenTK.Graphics public void Clear() { - //glyph_cache.Clear(); - throw new NotImplementedException(); + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + + TextOutput.Clear(); + Rasterizer.Clear(); } #endregion #region Obsolete + /// + /// Sets up OpenGL state for drawing text. + /// + [Obsolete] + public void Begin() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + + GraphicsContext.Assert(); + + float[] viewport = new float[4]; + + GL.GetFloat(GetPName.Viewport, viewport); + + // Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode, + // with size equal to the window (in pixels). + // While we could also render text in 3D mode, it would be very hard to get + // pixel-perfect precision. + GL.MatrixMode(MatrixMode.Projection); + GL.PushMatrix(); + GL.LoadIdentity(); + GL.Ortho(viewport[0], viewport[2], viewport[3], viewport[1], -1.0, 1.0); + + GL.MatrixMode(MatrixMode.Modelview); + GL.PushMatrix(); + GL.LoadIdentity(); + } + + /// + /// Restores OpenGL state. + /// + [Obsolete] + public void End() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + + GraphicsContext.Assert(); + + GL.MatrixMode(MatrixMode.Modelview); + GL.PopMatrix(); + + GL.MatrixMode(MatrixMode.Projection); + GL.PopMatrix(); + } + [Obsolete("Use TextPrinter.Print instead")] public void Draw(TextHandle handle) { @@ -204,5 +236,18 @@ namespace OpenTK.Graphics } #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!disposed) + { + TextOutput.Dispose(); + disposed = true; + } + } + + #endregion } } From 44240ad5984cd672d9846e847dcadcb6865dd47f Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 22:48:09 +0000 Subject: [PATCH 46/53] Make Mono use X11GdiPlusInternals regardless of platform. --- Source/OpenTK/Platform/GdiPlus.cs | 4 ++-- Source/OpenTK/Platform/X11/X11GdiPlusInternals.cs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/GdiPlus.cs b/Source/OpenTK/Platform/GdiPlus.cs index 24538796..16a1df42 100644 --- a/Source/OpenTK/Platform/GdiPlus.cs +++ b/Source/OpenTK/Platform/GdiPlus.cs @@ -26,10 +26,10 @@ namespace OpenTK.Platform static GdiPlus() { - if (Configuration.RunningOnWindows) + if (Configuration.RunningOnWindows && !Configuration.RunningOnMono) internals = new Windows.WinGdiPlusInternals(); else - internals = new X11.X11GdiPlusInternals(); + internals = new X11.X11GdiPlusInternals(); // This class is Mono-specific and works on all platforms. } #endregion diff --git a/Source/OpenTK/Platform/X11/X11GdiPlusInternals.cs b/Source/OpenTK/Platform/X11/X11GdiPlusInternals.cs index b197517a..45407b8d 100644 --- a/Source/OpenTK/Platform/X11/X11GdiPlusInternals.cs +++ b/Source/OpenTK/Platform/X11/X11GdiPlusInternals.cs @@ -14,6 +14,8 @@ using System.Reflection; namespace OpenTK.Platform.X11 { + // Note: This class is Mono-specific, not X11-specific! + // It works on all platforms (windows, linux, macos) as long as we are running on Mono. class X11GdiPlusInternals : IGdiPlusInternals { static readonly PropertyInfo native_graphics_property, native_font_property, native_string_format_property; From 522d1d17dce7d6980618727e463efef040386eb5 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 22:50:05 +0000 Subject: [PATCH 47/53] Added TextAlignment and TextDirection enums. Implemented RightToLeft and Vertical TextDirections (Vertical is glitchy). Implemented Near, Far and Center TextAlignments. Improved support for word wrapping. Removed alpha blending from GL11TextOutputProvider. --- Source/Utilities/Graphics/ITextPrinter.cs | 12 +- .../Graphics/Text/GL11TextOutputProvider.cs | 2 +- .../Graphics/Text/GL12TextOutputProvider.cs | 2 +- .../Graphics/Text/GdiPlusGlyphRasterizer .cs | 238 +++++++++++++----- Source/Utilities/Graphics/Text/TextBlock.cs | 12 +- Source/Utilities/Graphics/TextAlignment.cs | 19 ++ Source/Utilities/Graphics/TextDirection.cs | 19 ++ Source/Utilities/Graphics/TextPrinter.cs | 49 ++-- .../Utilities/Graphics/TextPrinterOptions.cs | 11 +- .../Graphics/{Text => }/TextQuality.cs | 2 +- 10 files changed, 272 insertions(+), 94 deletions(-) create mode 100644 Source/Utilities/Graphics/TextAlignment.cs create mode 100644 Source/Utilities/Graphics/TextDirection.cs rename Source/Utilities/Graphics/{Text => }/TextQuality.cs (79%) diff --git a/Source/Utilities/Graphics/ITextPrinter.cs b/Source/Utilities/Graphics/ITextPrinter.cs index d8f3ca8e..85375e6b 100644 --- a/Source/Utilities/Graphics/ITextPrinter.cs +++ b/Source/Utilities/Graphics/ITextPrinter.cs @@ -20,11 +20,15 @@ namespace OpenTK.Graphics void Begin(); void End(); void Print(string text, Font font, Color color); - void Print(string text, Font font, Color color, SizeF size); - void Print(string text, Font font, Color color, SizeF size, TextPrinterOptions options); + void Print(string text, Font font, Color color, RectangleF rect); + void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options); + void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment); + void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction); TextExtents Measure(string text, Font font); - TextExtents Measure(string text, Font font, SizeF size); - TextExtents Measure(string text, Font font, SizeF size, TextPrinterOptions options); + TextExtents Measure(string text, Font font, RectangleF rect); + TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options); + TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment); + TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction); [Obsolete("Use TextPrinter.Print instead")] void Draw(TextHandle handle); diff --git a/Source/Utilities/Graphics/Text/GL11TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL11TextOutputProvider.cs index 412ad4d4..c0686134 100644 --- a/Source/Utilities/Graphics/Text/GL11TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL11TextOutputProvider.cs @@ -37,7 +37,7 @@ namespace OpenTK.Graphics.Text protected override void SetColor(Color color) { - GL.Color4(color); + GL.Color3(color); } protected override TextQuality TextQuality diff --git a/Source/Utilities/Graphics/Text/GL12TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL12TextOutputProvider.cs index ba8575d2..3942f87c 100644 --- a/Source/Utilities/Graphics/Text/GL12TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL12TextOutputProvider.cs @@ -27,7 +27,7 @@ namespace OpenTK.Graphics.Text protected override void SetBlendFunction() { - GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); // For subpixel with color + GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor); } protected override void SetColor(Color color) diff --git a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs index 80f16652..d1825215 100644 --- a/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs +++ b/Source/Utilities/Graphics/Text/GdiPlusGlyphRasterizer .cs @@ -53,8 +53,12 @@ namespace OpenTK.Graphics.Text readonly ObjectPool text_extents_pool = new ObjectPool(); // Check the constructor, too, for additional flags. - static readonly StringFormat default_string_format = StringFormat.GenericTypographic; - static readonly StringFormat load_glyph_string_format = StringFormat.GenericDefault; + // Used for measuring text. Can set the leftToRight, rightToLeft, vertical and measure trailing spaces flags. + readonly StringFormat measure_string_format = new StringFormat(StringFormat.GenericDefault); + readonly StringFormat measure_string_format_tight = new StringFormat(StringFormat.GenericTypographic); + // Used for loading glyphs. Only use leftToRight! + readonly StringFormat load_glyph_string_format = new StringFormat(StringFormat.GenericDefault); + readonly StringFormat load_glyph_string_format_tight = new StringFormat(StringFormat.GenericTypographic); static readonly char[] newline_characters = new char[] { '\n', '\r' }; @@ -66,8 +70,6 @@ namespace OpenTK.Graphics.Text static GdiPlusGlyphRasterizer() { - default_string_format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; - using (Bitmap bmp = new Bitmap(1, 1)) using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp)) { @@ -75,7 +77,11 @@ namespace OpenTK.Graphics.Text } } - public GdiPlusGlyphRasterizer() { } + public GdiPlusGlyphRasterizer() + { + measure_string_format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces | StringFormatFlags.NoClip; + measure_string_format_tight.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; + } #endregion @@ -93,11 +99,29 @@ namespace OpenTK.Graphics.Text EnsureSurfaceSize(ref glyph_surface, ref glyph_renderer, glyph.Font); SetTextRenderingOptions(glyph_renderer, glyph.Font, quality); - 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); + RectangleF r2 = new RectangleF(); - RectangleF r2 = FindEdges(glyph_surface); + glyph_renderer.Clear(Color.Transparent); + + glyph_renderer.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, Point.Empty, //new Point(glyph_surface.Width, 0), + glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : load_glyph_string_format_tight); + + r2 = FindEdges(glyph_surface, true); + + //if ((default_string_format.FormatFlags & StringFormatFlags.DirectionRightToLeft) != 0) + //{ + // glyph_renderer.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, Point.Empty, //new Point(glyph_surface.Width, 0), + // load_glyph_string_format);//glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format); + + // r2 = FindEdges(glyph_surface, true); + //} + //else + //{ + // glyph_renderer.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, Point.Empty, + // load_glyph_string_format_tight); //glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format); + + // r2 = FindEdges(glyph_surface, false); + //} return glyph_surface.Clone(r2, System.Drawing.Imaging.PixelFormat.Format32bppArgb); } @@ -129,6 +153,8 @@ namespace OpenTK.Graphics.Text #endregion + #region Clear + public void Clear() { block_cache.Clear(); @@ -136,6 +162,8 @@ namespace OpenTK.Graphics.Text #endregion + #endregion + #region Private Members #region EnsureSurfaceSize @@ -194,15 +222,32 @@ namespace OpenTK.Graphics.Text TextExtents MeasureTextExtents(TextBlock block, TextQuality quality) { // Todo: Parse layout options: - //StringFormat format = default_string_format; - StringFormat format = default_string_format; + StringFormat format = block.Font.Italic ? measure_string_format : measure_string_format_tight; + //StringFormat format = measure_string_format_tight; + + if (block.Direction == TextDirection.Vertical) + format.FormatFlags |= StringFormatFlags.DirectionVertical; + else + format.FormatFlags &= ~StringFormatFlags.DirectionVertical; + + if (block.Direction == TextDirection.RightToLeft) + format.FormatFlags |= StringFormatFlags.DirectionRightToLeft; + else + format.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft; + + if (block.Alignment == TextAlignment.Near) + format.Alignment = StringAlignment.Near; + else if (block.Alignment == TextAlignment.Center) + format.Alignment = StringAlignment.Center; + else + format.Alignment = StringAlignment.Far; TextExtents extents = text_extents_pool.Acquire(); - RectangleF rect = new RectangleF(PointF.Empty, block.Bounds); + RectangleF rect = block.Bounds; // Work around Mono/GDI+ bug, which causes incorrect // text wraping when block.Bounds == SizeF.Empty. - if (block.Bounds == SizeF.Empty) + if (block.Bounds.Size == SizeF.Empty) rect.Size = MaximumGraphicsClipSize; SetTextRenderingOptions(graphics, block.Font, quality); @@ -211,7 +256,7 @@ namespace OpenTK.Graphics.Text IntPtr native_font = GdiPlus.GetNativeFont(block.Font); IntPtr native_string_format = GdiPlus.GetNativeStringFormat(format); - int height = 0; + float max_width = 0, max_height = 0; // It seems that the mere presence of \n and \r characters // is enough for Mono to botch the layout (even if these @@ -224,14 +269,26 @@ namespace OpenTK.Graphics.Text string[] lines = block.Text.Replace("\r", String.Empty).Split('\n'); foreach (string s in lines) { + float width, height; + extents.AddRange(MeasureGlyphExtents( - s, height, rect, - native_graphics, native_font, native_string_format)); - height += block.Font.Height; + ref block, s, + native_graphics, native_font, native_string_format, + ref rect, out width, out height)); + + if ((block.Direction & TextDirection.Vertical) == 0) + rect.Y += block.Font.Height; + else + rect.X += block.Font.Height; + + if (width > max_width) + max_width = width; + if (height > max_height) + max_height = height; } } - extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, extents[extents.Count - 1].Right, extents[extents.Count - 1].Bottom); + extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, max_width, max_height); return extents; } @@ -241,56 +298,87 @@ namespace OpenTK.Graphics.Text #region MeasureGlyphExtents // Gets the bounds of each character in a line of text. - // The line is processed in blocks of 32 characters (GdiPlus.MaxMeasurableCharacterRanges). - IEnumerable MeasureGlyphExtents(string text, int height, - RectangleF layoutRect, IntPtr native_graphics, IntPtr native_font, IntPtr native_string_format) + // Each line is processed in blocks of 32 characters (GdiPlus.MaxMeasurableCharacterRanges). + IEnumerable MeasureGlyphExtents( + ref TextBlock block, string text, + IntPtr native_graphics, IntPtr native_font, IntPtr native_string_format, + ref RectangleF layoutRect, out float max_width, out float max_height) { measured_glyphs.Clear(); + max_width = layoutRect.Left; + max_height = layoutRect.Top; + float last_line_width = 0, last_line_height = 0; - RectangleF rect = new RectangleF(); int current = 0; while (current < text.Length) - { - int num_characters = (text.Length - current) > GdiPlus.MaxMeasurableCharacterRanges ? - GdiPlus.MaxMeasurableCharacterRanges : - text.Length - current; - int status = 0; + { + int num_characters = (text.Length - current) > GdiPlus.MaxMeasurableCharacterRanges ? + GdiPlus.MaxMeasurableCharacterRanges : + text.Length - current; + int status = 0; - for (int i = 0; i < num_characters; i++) - { - if (text[current + i] == '\n' || text[current + i] == '\r') - throw new Exception(); + // Prepare the character ranges and region structs for the measurement. + for (int i = 0; i < num_characters; i++) + { + if (text[current + i] == '\n' || text[current + i] == '\r') + throw new NotSupportedException(); - characterRanges[i] = new CharacterRange(current + i, 1); + characterRanges[i] = new CharacterRange(current + i, 1); - IntPtr region; - status = GdiPlus.CreateRegion(out region); - regions[i] = region; - Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); - } + IntPtr region; + status = GdiPlus.CreateRegion(out region); + regions[i] = region; + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + } - status = GdiPlus.SetStringFormatMeasurableCharacterRanges(native_string_format, num_characters, characterRanges); - Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + status = GdiPlus.SetStringFormatMeasurableCharacterRanges(native_string_format, num_characters, characterRanges); + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); - status = GdiPlus.MeasureCharacterRanges(native_graphics, text, text.Length, - native_font, ref layoutRect, native_string_format, num_characters, regions); - Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + status = GdiPlus.MeasureCharacterRanges(native_graphics, text, text.Length, + native_font, ref layoutRect, native_string_format, num_characters, regions); + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); - for (int i = 0; i < num_characters; i++) - { - GdiPlus.GetRegionBounds(regions[i], native_graphics, ref rect); - Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); - GdiPlus.DeleteRegion(regions[i]); - Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + // Read back the results of the measurement. + for (int i = 0; i < num_characters; i++) + { + RectangleF rect = new RectangleF(); - rect.Y += height; - - //yield return rect; - measured_glyphs.Add(rect); - } + GdiPlus.GetRegionBounds(regions[i], native_graphics, ref rect); + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); + GdiPlus.DeleteRegion(regions[i]); + Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status)); - current += num_characters; - } + if (rect.Bottom > max_height) + max_height = rect.Bottom; + if (rect.Right > max_width) + max_width = rect.Right; + + if (rect.X > last_line_width) + last_line_width = rect.X; + if (rect.Y > last_line_height) + last_line_height = rect.Y; + + measured_glyphs.Add(rect); + } + + current += num_characters; + } + + // Make sure the current height is updated, if the the current line has wrapped due to word-wraping. + // Otherwise, the next line will overlap with the current one. + if (measured_glyphs.Count > 1) + { + if ((block.Direction & TextDirection.Vertical) == 0) + { + if (layoutRect.Y < last_line_height) + layoutRect.Y = last_line_height; + } + else + { + if (layoutRect.X < last_line_width) + layoutRect.X = last_line_width; + } + } return measured_glyphs; } @@ -305,18 +393,22 @@ namespace OpenTK.Graphics.Text #pragma warning restore 0649 - Rectangle FindEdges(Bitmap bmp) + // Note: The bool parameter is not used at this point. + // We might need it if we ever load true rightToLeft glyphs. + Rectangle FindEdges(Bitmap bmp, bool rightToLeft) { BitmapData data = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - - Rectangle rect = Rectangle.FromLTRB( - FindLeftEdge(bmp, data.Scan0), - FindTopEdge(bmp, data.Scan0), - FindRightEdge(bmp, data.Scan0), - FindBottomEdge(bmp, data.Scan0)); + + //Rectangle rect = rightToLeft ? + // Rectangle.FromLTRB(FindLeftEdge(bmp, data.Scan0), 0, bmp.Width - 1, FindBottomEdge(bmp, data.Scan0)) : + // Rectangle.FromLTRB(0, 0, FindRightEdge(bmp, data.Scan0), FindBottomEdge(bmp, data.Scan0)); + + Rectangle rect = + Rectangle.FromLTRB(0, 0, FindRightEdge(bmp, data.Scan0), FindBottomEdge(bmp, data.Scan0)); + //Rectangle.FromLTRB(FindLeftEdge(bmp, data.Scan0), 0, FindRightEdge(bmp, data.Scan0), FindBottomEdge(bmp, data.Scan0)); bmp.UnlockBits(data); @@ -331,8 +423,15 @@ namespace OpenTK.Graphics.Text int FindLeftEdge(Bitmap bmp, IntPtr ptr) { - // Don't trim the left edge, because the layout engine expects it to be 0. - return 0; + for (int x = 0; x < bmp.Width; x++) + for (int y = 0; y < bmp.Height; y++) + unsafe + { + if (((Pixel*)(ptr) + y * bmp.Width + x)->A != 0) + return x; + } + + return bmp.Width - 1; } int FindRightEdge(Bitmap bmp, IntPtr ptr) @@ -350,8 +449,15 @@ namespace OpenTK.Graphics.Text int FindTopEdge(Bitmap bmp, IntPtr ptr) { - // Don't trim the top edge, because the layout engine expects it to be 0. - return 0; + for (int y = 0; y < bmp.Height; y++) + for (int x = 0; x < bmp.Width; x++) + unsafe + { + if (((Pixel*)(ptr) + y * bmp.Width + x)->A != 0) + return y; + } + + return bmp.Height - 1; } int FindBottomEdge(Bitmap bmp, IntPtr ptr) diff --git a/Source/Utilities/Graphics/Text/TextBlock.cs b/Source/Utilities/Graphics/Text/TextBlock.cs index 579acd11..006d3b9d 100644 --- a/Source/Utilities/Graphics/Text/TextBlock.cs +++ b/Source/Utilities/Graphics/Text/TextBlock.cs @@ -41,22 +41,28 @@ namespace OpenTK.Graphics.Text public readonly Font Font; - public readonly SizeF Bounds; + public readonly RectangleF Bounds; public readonly TextPrinterOptions Options; - public int UsageCount; // Used to identify old and unused blocks of text. + public readonly TextAlignment Alignment; + + public readonly TextDirection Direction; + + public readonly int UsageCount; #endregion #region Constructors - public TextBlock(string text, Font font, TextPrinterOptions options, SizeF bounds) + public TextBlock(string text, Font font, RectangleF bounds, TextPrinterOptions options, TextAlignment alignment, TextDirection direction) { Text = text; Font = font; Bounds = bounds; Options = options; + Alignment = alignment; + Direction = direction; UsageCount = 0; } diff --git a/Source/Utilities/Graphics/TextAlignment.cs b/Source/Utilities/Graphics/TextAlignment.cs new file mode 100644 index 00000000..4d88cf3d --- /dev/null +++ b/Source/Utilities/Graphics/TextAlignment.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics +{ + /// + /// Defines available alignments for text. + /// + public enum TextAlignment + { + /// The text is aligned to the near side (left for left-to-right text and right for right-to-left text). + Near = 0, + /// The text is aligned to the center. + Center, + /// The text is aligned to the far side (right for left-to-right text and left for right-to-left text). + Far + } +} diff --git a/Source/Utilities/Graphics/TextDirection.cs b/Source/Utilities/Graphics/TextDirection.cs new file mode 100644 index 00000000..151ca784 --- /dev/null +++ b/Source/Utilities/Graphics/TextDirection.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics +{ + /// + /// Defines available directions for text layout. + /// + public enum TextDirection + { + /// The text is layed out from left to right. + LeftToRight, + /// The text is layed out from right to left. + RightToLeft, + /// The text is layed out vertically. + Vertical + } +} diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index 156d954b..6f46c6db 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -64,23 +64,33 @@ namespace OpenTK.Graphics public void Print(string text, Font font, Color color) { - Print(text, font, color, SizeF.Empty, TextPrinterOptions.Default); + Print(text, font, color, RectangleF.Empty, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight); } - public void Print(string text, Font font, Color color, SizeF size) + public void Print(string text, Font font, Color color, RectangleF rect) { - Print(text, font, color, size, TextPrinterOptions.Default); + Print(text, font, color, rect, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight); } - public void Print(string text, Font font, Color color, SizeF size, TextPrinterOptions options) + public void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options) + { + Print(text, font, color, rect, options, TextAlignment.Near, TextDirection.LeftToRight); + } + + public void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment) + { + Print(text, font, color, rect, options, alignment, TextDirection.LeftToRight); + } + + public void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction) { if (disposed) throw new ObjectDisposedException(this.GetType().ToString()); - if (!ValidateParameters(text, font, size)) + if (!ValidateParameters(text, font, rect)) return; - TextOutput.Print(new TextBlock(text, font, options, size), color, Rasterizer); + TextOutput.Print(new TextBlock(text, font, rect, options, alignment, direction), color, Rasterizer); } #endregion @@ -89,23 +99,34 @@ namespace OpenTK.Graphics public TextExtents Measure(string text, Font font) { - return Measure(text, font, SizeF.Empty, TextPrinterOptions.Default); + return Measure(text, font, RectangleF.Empty, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight); } - public TextExtents Measure(string text, Font font, SizeF size) + public TextExtents Measure(string text, Font font, RectangleF rect) { - return Measure(text, font, size, TextPrinterOptions.Default); + return Measure(text, font, rect, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight); } - public TextExtents Measure(string text, Font font, SizeF size, TextPrinterOptions options) + public TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options) + { + return Measure(text, font, rect, options, TextAlignment.Near, TextDirection.LeftToRight); + } + + + public TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment) + { + return Measure(text, font, rect, options, alignment, TextDirection.LeftToRight); + } + + public TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction) { if (disposed) throw new ObjectDisposedException(this.GetType().ToString()); - if (!ValidateParameters(text, font, size)) + if (!ValidateParameters(text, font, rect)) return TextExtents.Empty; - return Rasterizer.MeasureText(new TextBlock(text, font, options, size)); + return Rasterizer.MeasureText(new TextBlock(text, font, rect, options, alignment, direction)); } #endregion @@ -223,13 +244,13 @@ namespace OpenTK.Graphics #region Static Members - static bool ValidateParameters(string text, Font font, SizeF size) + static bool ValidateParameters(string text, Font font, RectangleF rect) { if (String.IsNullOrEmpty(text)) return false; if (font == null) throw new ArgumentNullException("font"); - if (size.Width < 0 || size.Height < 0) + if (rect.Width < 0 || rect.Height < 0) throw new ArgumentOutOfRangeException("size"); return true; diff --git a/Source/Utilities/Graphics/TextPrinterOptions.cs b/Source/Utilities/Graphics/TextPrinterOptions.cs index 15bd1739..e8e530dd 100644 --- a/Source/Utilities/Graphics/TextPrinterOptions.cs +++ b/Source/Utilities/Graphics/TextPrinterOptions.cs @@ -4,12 +4,15 @@ using System.Text; namespace OpenTK.Graphics { + /// + /// Defines available options for the TextPrinter. + /// [Flags] public enum TextPrinterOptions { - Default = 0, - NoCache = 1, - RightToLeft = 2, - Vertical = 4, + /// The TextPrinter will use default printing options. + Default = 0x0000, + /// The TextPrinter will not cache text blocks as they are measured or printed. + NoCache = 0x0001, } } diff --git a/Source/Utilities/Graphics/Text/TextQuality.cs b/Source/Utilities/Graphics/TextQuality.cs similarity index 79% rename from Source/Utilities/Graphics/Text/TextQuality.cs rename to Source/Utilities/Graphics/TextQuality.cs index 7ed091f5..3a659fcb 100644 --- a/Source/Utilities/Graphics/Text/TextQuality.cs +++ b/Source/Utilities/Graphics/TextQuality.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OpenTK.Graphics.Text +namespace OpenTK.Graphics { public enum TextQuality { From 9857e2f13cbea0fc762ce16c3f047556319e1bcd Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 22:51:42 +0000 Subject: [PATCH 48/53] Added debug message for the detected configuration. --- Source/OpenTK/Configuration.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/OpenTK/Configuration.cs b/Source/OpenTK/Configuration.cs index 7acee9ea..729e7242 100644 --- a/Source/OpenTK/Configuration.cs +++ b/Source/OpenTK/Configuration.cs @@ -62,6 +62,10 @@ namespace OpenTK Type t = Type.GetType("Mono.Runtime"); if (t != null) runningOnMono = true; + + Debug.Print("Detected configuration: {0} / {1}", + RunningOnWindows ? "Windows" : RunningOnLinux ? "Linux" : RunningOnOSX ? "MacOS" : RunningOnX11 ? "X11" : "Unknown Platform", + RunningOnMono ? "Mono" : ".Net"); } #endregion From c18b5227634bef2325e93ee7d33c48418803c8f8 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 22:52:24 +0000 Subject: [PATCH 49/53] Exercise TextAlignment and TextDirection options. --- Source/Examples/Tutorial/Text.cs | 39 ++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Source/Examples/Tutorial/Text.cs b/Source/Examples/Tutorial/Text.cs index 08a198e4..0a929c5a 100644 --- a/Source/Examples/Tutorial/Text.cs +++ b/Source/Examples/Tutorial/Text.cs @@ -24,11 +24,10 @@ namespace Examples.Tutorial public class Text : GameWindow { Font serif = new Font(FontFamily.GenericSerif, 16.0f); - Font sans = new Font(FontFamily.GenericSansSerif, 48.0f, FontStyle.Italic); + Font sans = new Font(FontFamily.GenericSansSerif, 18.0f); TextPrinter text = new TextPrinter(); - //string poem = new StreamReader("Data/Poem.txt").ReadToEnd(); - string poem = "The quick brown fox jumped over the lazy dogs!\n\nKerning: Wo\nLigatures: ffi, fft"; + string poem = new StreamReader("Data/Poem.txt").ReadToEnd(); int lines; // How many lines the poem contains. float scroll_speed; @@ -44,7 +43,7 @@ namespace Examples.Tutorial public override void OnLoad(EventArgs e) { - GL.ClearColor(Color.SteelBlue); + GL.ClearColor(Color.MidnightBlue); current_position = initial_position; scroll_speed = -1.0f; @@ -57,8 +56,7 @@ namespace Examples.Tutorial if (c == '\n') lines++; - warparound_position = - -(lines + 1) * serif.Height; + warparound_position = -(lines + 1) * serif.Height; } #endregion @@ -82,9 +80,7 @@ namespace Examples.Tutorial GL.Viewport(0, 0, Width, Height); initial_position = Height + serif.Height; // Start one line below the screen. - - warparound_position = - -(lines + 1) * serif.Height; + warparound_position = -(lines + 1) * serif.Height; } #endregion @@ -94,11 +90,11 @@ namespace Examples.Tutorial public override void OnUpdateFrame(UpdateFrameEventArgs e) { if (Keyboard[Key.Space]) - scroll_speed = 0.0f; + scroll_speed = 0; if (Keyboard[Key.Down]) - scroll_speed += 1; + scroll_speed += 10; if (Keyboard[Key.Up]) - scroll_speed -= 1; + scroll_speed -= 10; if (Keyboard[Key.Escape]) this.Exit(); } @@ -111,10 +107,17 @@ namespace Examples.Tutorial { GL.Clear(ClearBufferMask.ColorBufferBit); + GL.MatrixMode(MatrixMode.Projection); + GL.LoadIdentity(); + GL.Ortho(-1, 1, -1, 1, -1, 1); + + GL.MatrixMode(MatrixMode.Modelview); + GL.LoadIdentity(); + // We'll start printing from the lower left corner of the screen. The text // will slowly move updwards - the user can control the movement speed with // the keyboard arrows and the space bar. - current_position += scroll_speed * (float)e.ScaleFactor; + current_position += scroll_speed * (float)e.Time; if (scroll_speed > 0.0f && current_position > initial_position) current_position = warparound_position; else if (scroll_speed < 0.0f && current_position < warparound_position) @@ -129,11 +132,13 @@ namespace Examples.Tutorial // Print FPS counter. Since the counter changes per frame, // it shouldn't be cached (TextPrinterOptions.NoCache). - text.Print((1.0 / e.Time).ToString("F2"), sans, Color.LightYellow, RectangleF.Empty, TextPrinterOptions.NoCache); - + text.Print((1.0 / e.Time).ToString("F2"), sans, Color.SpringGreen, new RectangleF(0, 0, Width, 0), TextPrinterOptions.NoCache, TextAlignment.Far); + // Print the actual text. - text.Print(poem, serif, Color.White, new RectangleF(0, current_position, 0, 0), TextPrinterOptions.Default); - + GL.Translate(0, current_position, 0); + text.Print(poem, serif, Color.White, new RectangleF(Width / 2, 0, Width / 2, 0), TextPrinterOptions.Default, TextAlignment.Far); + text.Print(poem, serif, Color.White, new RectangleF(0, 0, Width / 2, 0)); + text.End(); SwapBuffers(); From 538198776b61b8e36e9e01e968404738b390ec46 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 23:10:09 +0000 Subject: [PATCH 50/53] Moved TextExtents to OpenTK.Graphics. Added documentation to all public classes and interfaces. --- Source/Utilities/Graphics/ITextPrinter.cs | 112 +++++++++++++++++- .../Graphics/{Text => }/TextExtents.cs | 44 ++++--- Source/Utilities/Graphics/TextPrinter.cs | 90 +++++++++++++- Source/Utilities/Graphics/TextQuality.cs | 7 ++ 4 files changed, 235 insertions(+), 18 deletions(-) rename Source/Utilities/Graphics/{Text => }/TextExtents.cs (74%) diff --git a/Source/Utilities/Graphics/ITextPrinter.cs b/Source/Utilities/Graphics/ITextPrinter.cs index 85375e6b..4f72e74a 100644 --- a/Source/Utilities/Graphics/ITextPrinter.cs +++ b/Source/Utilities/Graphics/ITextPrinter.cs @@ -17,19 +17,125 @@ namespace OpenTK.Graphics /// public interface ITextPrinter : IDisposable { - void Begin(); - void End(); + #region Print + + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. void Print(string text, Font font, Color color); + + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. void Print(string text, Font font, Color color, RectangleF rect); + + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to print text. void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options); + + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to print text. + /// The OpenTK.Graphics.TextAlignment that will be used to print text. void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment); + + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to print text. + /// The OpenTK.Graphics.TextAlignment that will be used to print text. + /// The OpenTK.Graphics.TextDirection that will be used to print text. void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction); + + #endregion + + #region Measure + + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. TextExtents Measure(string text, Font font); + + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to measure text. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. TextExtents Measure(string text, Font font, RectangleF rect); + + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to measure text. + /// The OpenTK.Graphics.TextAlignment that will be used to measure text. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options); + + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to measure text. + /// The OpenTK.Graphics.TextAlignment that will be used to measure text. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment); + + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to measure text. + /// The OpenTK.Graphics.TextAlignment that will be used to measure text. + /// The OpenTK.Graphics.TextDirection that will be used to measure text. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction); + #endregion + + #region Obsolete + + [Obsolete] + void Begin(); + + [Obsolete] + void End(); + [Obsolete("Use TextPrinter.Print instead")] void Draw(TextHandle handle); @@ -38,5 +144,7 @@ namespace OpenTK.Graphics [Obsolete("Use TextPrinter.Print instead")] void Prepare(string text, TextureFont font, out TextHandle handle); + + #endregion } } diff --git a/Source/Utilities/Graphics/Text/TextExtents.cs b/Source/Utilities/Graphics/TextExtents.cs similarity index 74% rename from Source/Utilities/Graphics/Text/TextExtents.cs rename to Source/Utilities/Graphics/TextExtents.cs index 03a923a2..6362f42f 100644 --- a/Source/Utilities/Graphics/Text/TextExtents.cs +++ b/Source/Utilities/Graphics/TextExtents.cs @@ -30,9 +30,11 @@ using System.Collections.Generic; using System.Text; using System.Drawing; -namespace OpenTK.Graphics.Text +namespace OpenTK.Graphics { - // Holds layout information about a TextBlock. + /// + /// Holds the results of a text measurement. + /// public class TextExtents : IDisposable { #region Fields @@ -54,39 +56,42 @@ namespace OpenTK.Graphics.Text #region Public Members + /// + /// Gets the bounding box of the measured text. + /// public RectangleF BoundingBox { get { return text_extents; } internal set { text_extents = value; } } + /// + /// Gets the extents of each glyph in the measured text. + /// + /// The index of the glyph. + /// The extents of the specified glyph. public RectangleF this[int i] { get { return glyph_extents[i]; } internal set { glyph_extents[i] = value; } } + /// + /// Gets the extents of each glyph in the measured text. + /// public IEnumerable GlyphExtents { - get - { - return (IEnumerable)glyph_extents; - } + get { return (IEnumerable)glyph_extents; } } + /// + /// Gets the number of the measured glyphs. + /// public int Count { get { return glyph_extents.Count; } } - public TextExtents Clone() - { - TextExtents extents = new TextExtents(); - extents.glyph_extents.AddRange(GlyphExtents); - extents.BoundingBox = BoundingBox; - return extents; - } - #endregion #region Internal Members @@ -107,10 +112,21 @@ namespace OpenTK.Graphics.Text glyph_extents.Clear(); } + internal TextExtents Clone() + { + TextExtents extents = new TextExtents(); + extents.glyph_extents.AddRange(GlyphExtents); + extents.BoundingBox = BoundingBox; + return extents; + } + #endregion #region IDisposable Members + /// + /// Frees the resources consumed by this TextExtents instance. + /// public virtual void Dispose() { } diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index 6f46c6db..a96757d0 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -41,11 +41,15 @@ namespace OpenTK.Graphics #region Constructors /// - /// Constructs a new TextPrinter object. + /// Constructs a new TextPrinter instance. /// public TextPrinter() : this(null, null, TextQuality.Default) { } + /// + /// Constructs a new TextPrinter instance with the specified TextQuality level. + /// + /// The desired TextQuality of this TextPrinter. public TextPrinter(TextQuality quality) : this(null, null, quality) { } @@ -62,26 +66,66 @@ namespace OpenTK.Graphics #region Print + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. public void Print(string text, Font font, Color color) { Print(text, font, color, RectangleF.Empty, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight); } + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. public void Print(string text, Font font, Color color, RectangleF rect) { Print(text, font, color, rect, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight); } + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to print text. public void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options) { Print(text, font, color, rect, options, TextAlignment.Near, TextDirection.LeftToRight); } + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to print text. + /// The OpenTK.Graphics.TextAlignment that will be used to print text. public void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment) { Print(text, font, color, rect, options, alignment, TextDirection.LeftToRight); } + /// + /// Prints text using the specified color and layout options. + /// + /// The System.String to print. + /// The System.Drawing.Font that will be used to print text. + /// The System.Drawing.Color that will be used to print text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to print text. + /// The OpenTK.Graphics.TextAlignment that will be used to print text. + /// The OpenTK.Graphics.TextDirection that will be used to print text. public void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction) { if (disposed) @@ -97,27 +141,66 @@ namespace OpenTK.Graphics #region Measure + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. public TextExtents Measure(string text, Font font) { return Measure(text, font, RectangleF.Empty, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight); } + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. public TextExtents Measure(string text, Font font, RectangleF rect) { return Measure(text, font, rect, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight); } + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to measure text. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. public TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options) { return Measure(text, font, rect, options, TextAlignment.Near, TextDirection.LeftToRight); } - + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to measure text. + /// The OpenTK.Graphics.TextAlignment that will be used to measure text. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. public TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment) { return Measure(text, font, rect, options, alignment, TextDirection.LeftToRight); } + /// + /// Measures text using the specified layout options. + /// + /// The System.String to measure. + /// The System.Drawing.Font that will be used to measure text. + /// The System.Drawing.Rectangle that defines the bounds for text layout. + /// The OpenTK.Graphics.TextPrinterOptions that will be used to measure text. + /// The OpenTK.Graphics.TextAlignment that will be used to measure text. + /// The OpenTK.Graphics.TextDirection that will be used to measure text. + /// An OpenTK.Graphics.TextExtents instance that contains the results of the measurement. public TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction) { if (disposed) @@ -260,6 +343,9 @@ namespace OpenTK.Graphics #region IDisposable Members + /// + /// Frees the resources consumed by this TextPrinter object. + /// public void Dispose() { if (!disposed) diff --git a/Source/Utilities/Graphics/TextQuality.cs b/Source/Utilities/Graphics/TextQuality.cs index 3a659fcb..67275d1c 100644 --- a/Source/Utilities/Graphics/TextQuality.cs +++ b/Source/Utilities/Graphics/TextQuality.cs @@ -4,11 +4,18 @@ using System.Text; namespace OpenTK.Graphics { + /// + /// Defines available quality levels for text printing. + /// public enum TextQuality { + /// Use the default quality, as specified by the operating system. Default = 0, + /// Use fast, low quality text (typically non-antialiased) . Low, + /// Use medium quality text (typically grayscale antialiased). Medium, + /// Use slow, high quality text (typically subpixel antialiased). High } } From 31e425f1cda66c225c7ed0773e0292e0b6d15789 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 23:40:48 +0000 Subject: [PATCH 51/53] TextPrinter.Begin() / End() are no longer deprecated. --- Source/Utilities/Graphics/ITextPrinter.cs | 18 +++++- .../Graphics/Text/GL1TextOutputProvider.cs | 62 +++++++++++++++++++ .../Graphics/Text/ITextOutputProvider.cs | 2 + Source/Utilities/Graphics/TextPrinter.cs | 51 +++++---------- 4 files changed, 93 insertions(+), 40 deletions(-) diff --git a/Source/Utilities/Graphics/ITextPrinter.cs b/Source/Utilities/Graphics/ITextPrinter.cs index 4f72e74a..e5cb68dc 100644 --- a/Source/Utilities/Graphics/ITextPrinter.cs +++ b/Source/Utilities/Graphics/ITextPrinter.cs @@ -128,14 +128,26 @@ namespace OpenTK.Graphics #endregion - #region Obsolete + #region Begin - [Obsolete] + /// + /// Sets up a resolution-dependent orthographic projection. + /// void Begin(); - [Obsolete] + #endregion + + /// + /// Restores the projection and modelview matrices to their previous state. + /// + #region End + void End(); + #endregion + + #region Obsolete + [Obsolete("Use TextPrinter.Print instead")] void Draw(TextHandle handle); diff --git a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs index c93177a2..6731f35e 100644 --- a/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs @@ -40,6 +40,12 @@ namespace OpenTK.Graphics.Text Dictionary> active_lists = new Dictionary>(); Queue> inactive_lists = new Queue>(); + #pragma warning disable 0649 + + struct Viewport { public float Left, Top, Right, Bottom; } + + #pragma warning restore 0649 + bool disposed; #endregion @@ -164,6 +170,62 @@ namespace OpenTK.Graphics.Text #endregion + #region Begin + + public void Begin() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + + GraphicsContext.Assert(); + + int current_matrix; + GL.GetInteger(GetPName.MatrixMode, out current_matrix); + + Viewport viewport = new Viewport(); + GL.GetFloat(GetPName.Viewport, out viewport.Left); + + // Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode, + // with size equal to the window (in pixels). + // While we could also render text in 3D mode, it would be very hard to get + // pixel-perfect precision. + GL.MatrixMode(MatrixMode.Projection); + GL.PushMatrix(); + GL.LoadIdentity(); + GL.Ortho(viewport.Left, viewport.Right, viewport.Bottom, viewport.Top, -1.0, 1.0); + + GL.MatrixMode(MatrixMode.Modelview); + GL.PushMatrix(); + GL.LoadIdentity(); + + GL.MatrixMode((MatrixMode)current_matrix); + } + + #endregion + + #region End + + public void End() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + + GraphicsContext.Assert(); + + int current_matrix; + GL.GetInteger(GetPName.MatrixMode, out current_matrix); + + GL.MatrixMode(MatrixMode.Modelview); + GL.PopMatrix(); + + GL.MatrixMode(MatrixMode.Projection); + GL.PopMatrix(); + + GL.MatrixMode((MatrixMode)current_matrix); + } + + #endregion + #endregion #region Protected Members diff --git a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs index ce1aaf93..826dc890 100644 --- a/Source/Utilities/Graphics/Text/ITextOutputProvider.cs +++ b/Source/Utilities/Graphics/Text/ITextOutputProvider.cs @@ -36,5 +36,7 @@ namespace OpenTK.Graphics.Text { void Print(TextBlock block, Color color, IGlyphRasterizer rasterizer); void Clear(); + void Begin(); + void End(); } } diff --git a/Source/Utilities/Graphics/TextPrinter.cs b/Source/Utilities/Graphics/TextPrinter.cs index a96757d0..defb3c02 100644 --- a/Source/Utilities/Graphics/TextPrinter.cs +++ b/Source/Utilities/Graphics/TextPrinter.cs @@ -214,7 +214,7 @@ namespace OpenTK.Graphics #endregion - #region Clear() + #region Clear public void Clear() { @@ -227,55 +227,32 @@ namespace OpenTK.Graphics #endregion - #region Obsolete + #region Begin /// - /// Sets up OpenGL state for drawing text. + /// Sets up a resolution-dependent orthographic projection. /// - [Obsolete] public void Begin() { - if (disposed) - throw new ObjectDisposedException(this.GetType().ToString()); - - GraphicsContext.Assert(); - - float[] viewport = new float[4]; - - GL.GetFloat(GetPName.Viewport, viewport); - - // Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode, - // with size equal to the window (in pixels). - // While we could also render text in 3D mode, it would be very hard to get - // pixel-perfect precision. - GL.MatrixMode(MatrixMode.Projection); - GL.PushMatrix(); - GL.LoadIdentity(); - GL.Ortho(viewport[0], viewport[2], viewport[3], viewport[1], -1.0, 1.0); - - GL.MatrixMode(MatrixMode.Modelview); - GL.PushMatrix(); - GL.LoadIdentity(); + TextOutput.Begin(); } + #endregion + + #region Begin + /// - /// Restores OpenGL state. + /// Restores the projection and modelview matrices to their previous state. /// - [Obsolete] public void End() { - if (disposed) - throw new ObjectDisposedException(this.GetType().ToString()); - - GraphicsContext.Assert(); - - GL.MatrixMode(MatrixMode.Modelview); - GL.PopMatrix(); - - GL.MatrixMode(MatrixMode.Projection); - GL.PopMatrix(); + TextOutput.End(); } + #endregion + + #region Obsolete + [Obsolete("Use TextPrinter.Print instead")] public void Draw(TextHandle handle) { From ef4ab16e30cffd165d64c68ce3a13590e82ba40d Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 23:41:29 +0000 Subject: [PATCH 52/53] Modified to use new Text interface. --- Source/Examples/Tutorial/Text.cs | 9 +------ Source/Examples/WinForms/FontRendering.cs | 31 ++++++++++++----------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/Source/Examples/Tutorial/Text.cs b/Source/Examples/Tutorial/Text.cs index 0a929c5a..3dc9925e 100644 --- a/Source/Examples/Tutorial/Text.cs +++ b/Source/Examples/Tutorial/Text.cs @@ -107,13 +107,6 @@ namespace Examples.Tutorial { GL.Clear(ClearBufferMask.ColorBufferBit); - GL.MatrixMode(MatrixMode.Projection); - GL.LoadIdentity(); - GL.Ortho(-1, 1, -1, 1, -1, 1); - - GL.MatrixMode(MatrixMode.Modelview); - GL.LoadIdentity(); - // We'll start printing from the lower left corner of the screen. The text // will slowly move updwards - the user can control the movement speed with // the keyboard arrows and the space bar. @@ -140,7 +133,7 @@ namespace Examples.Tutorial text.Print(poem, serif, Color.White, new RectangleF(0, 0, Width / 2, 0)); text.End(); - + SwapBuffers(); } diff --git a/Source/Examples/WinForms/FontRendering.cs b/Source/Examples/WinForms/FontRendering.cs index 07363c64..e4e66356 100644 --- a/Source/Examples/WinForms/FontRendering.cs +++ b/Source/Examples/WinForms/FontRendering.cs @@ -14,10 +14,11 @@ namespace Examples.WinForms { #region Fields - float[] sizes = new float[] { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 28, 32, 36, 42, 48 }; + //float[] sizes = new float[] { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 28, 32, 36, 42, 48 }; + float[] sizes = new float[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 24 }; List fonts = new List(); - TextPrinter text = new TextPrinter(); + TextPrinter printer = new TextPrinter(); #endregion @@ -26,6 +27,7 @@ namespace Examples.WinForms public FontRendering() { InitializeComponent(); + ResizeRedraw = true; UpdateFontList(fontDialog.Font); glControl1_Resize(this, EventArgs.Empty); @@ -37,11 +39,13 @@ namespace Examples.WinForms void UpdateFontList(Font base_font) { + printer.Clear(); + foreach (Font font in fonts) font.Dispose(); fonts.Clear(); foreach (float size in sizes) - fonts.Add(new Font(base_font.Name, size, base_font.Style)); + fonts.Add(new Font(base_font.Name, base_font.SizeInPoints + size, base_font.Style)); } #endregion @@ -51,7 +55,6 @@ namespace Examples.WinForms private void glControl1_Load(object sender, EventArgs e) { glControl1.MakeCurrent(); - GL.ClearColor(Color.SteelBlue); } private void changeFont_Click(object sender, EventArgs e) @@ -70,24 +73,22 @@ namespace Examples.WinForms private void glControl1_Paint(object sender, PaintEventArgs e) { - GL.ClearColor(Color.Red); glControl1.MakeCurrent(); - //GL.ClearColor(Color.Gainsboro); + GL.ClearColor(Color.MidnightBlue); GL.Clear(ClearBufferMask.ColorBufferBit); - //GL.Color4(Color.Blue); - //GL.BlendColor(0, 0, 0, 0); + + GL.MatrixMode(MatrixMode.Projection); + GL.LoadIdentity(); + GL.Ortho(0, glControl1.ClientSize.Width, glControl1.ClientSize.Height, 0, -1, 1); + GL.MatrixMode(MatrixMode.Modelview); + GL.LoadIdentity(); - //text.Begin(); - - RectangleF rect = new RectangleF(); foreach (Font font in fonts) { - text.Print(textBox1.Text, font, Color.White, rect); - rect.Y += font.Height; + printer.Print(textBox1.Text, font, Color.White); + GL.Translate(0, font.Height + 5, 0); } - //text.End(); - glControl1.SwapBuffers(); } From b75b50acb2c5e30efe0b04eb35cbd93011889d58 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 12 Feb 2009 23:42:11 +0000 Subject: [PATCH 53/53] Changed example color to midnight blue. --- Source/Examples/OpenGL/GluTessellation.cs | 2 +- Source/Examples/OpenGL/JuliaSetFractal.cs | 2 +- Source/Examples/Tests/GameWindowStates.cs | 10 ++++++---- Source/Examples/Tutorial/Fonts.cs | 2 +- Source/Examples/Tutorial/T01_Simple_Window.cs | 4 ++-- Source/Examples/Tutorial/T03_Immediate_Mode_Cube.cs | 4 ++-- Source/Examples/Tutorial/T07_Display_Lists_Flower.cs | 2 +- Source/Examples/Tutorial/T10_GLSL_Cube.cs | 2 +- Source/Examples/Tutorial/Textures.cs | 2 +- Source/Examples/WinForms/W02_Immediate_Mode_Cube.cs | 2 +- 10 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Source/Examples/OpenGL/GluTessellation.cs b/Source/Examples/OpenGL/GluTessellation.cs index 5192532a..110d85dd 100644 --- a/Source/Examples/OpenGL/GluTessellation.cs +++ b/Source/Examples/OpenGL/GluTessellation.cs @@ -168,7 +168,7 @@ namespace Examples new double[] {400.0, 150.0, 0.0, 0.0, 1.0, 0.0} }; - GL.ClearColor(System.Drawing.Color.SteelBlue); + GL.ClearColor(System.Drawing.Color.MidnightBlue); tess = Glu.NewTess(); startList = GL.GenLists(3); diff --git a/Source/Examples/OpenGL/JuliaSetFractal.cs b/Source/Examples/OpenGL/JuliaSetFractal.cs index df5658a0..e157fe21 100644 --- a/Source/Examples/OpenGL/JuliaSetFractal.cs +++ b/Source/Examples/OpenGL/JuliaSetFractal.cs @@ -289,7 +289,7 @@ namespace Examples.Tutorial // Then, render the fps: GL.UseProgram(0); printer.Begin(); - printer.Print((1 / e.Time).ToString("F2"), font, Color.PaleGoldenrod, RectangleF .Empty, TextPrinterOptions.NoCache); + printer.Print((1 / e.Time).ToString("F2"), font, Color.PaleGoldenrod, RectangleF.Empty, TextPrinterOptions.NoCache); printer.End(); SwapBuffers(); diff --git a/Source/Examples/Tests/GameWindowStates.cs b/Source/Examples/Tests/GameWindowStates.cs index 862989c3..c722c478 100644 --- a/Source/Examples/Tests/GameWindowStates.cs +++ b/Source/Examples/Tests/GameWindowStates.cs @@ -67,7 +67,7 @@ namespace Examples.Tests this.Keyboard.KeyRepeat = true; this.Keyboard.KeyUp += new OpenTK.Input.KeyUpEvent(Keyboard_KeyUp); - GL.ClearColor(System.Drawing.Color.SteelBlue); + GL.ClearColor(System.Drawing.Color.MidnightBlue); } void Keyboard_KeyUp(KeyboardDevice sender, Key key) @@ -119,11 +119,13 @@ namespace Examples.Tests printer.Begin(); printer.Print("Instructions:", font, Color.White); - printer.Print(String.Format("1 - cycle through window styles (current: {0}).", this.WindowState), font, Color.White, new RectangleF(0, font.Height, 0, 0)); - printer.Print(String.Format("2 - cycle through window borders (current: {0}).", this.WindowBorder), font, Color.White, new RectangleF(0, 2 * font.Height, 0, 0)); + GL.Translate(0, font.Height, 0); + printer.Print(String.Format("1 - cycle through window styles (current: {0}).", this.WindowState), font, Color.White, RectangleF.Empty); + GL.Translate(0, font.Height, 0); + printer.Print(String.Format("2 - cycle through window borders (current: {0}).", this.WindowBorder), font, Color.White, RectangleF.Empty); GL.Translate(0, font.Height, 0); printer.Print(String.Format("3 - toggle fullscreen (current: {0}).", - this.WindowState == WindowState.Fullscreen ? "enabled" : "disabled"), font, Color.White, new RectangleF(0, 2 * font.Height, 0, 0)); + this.WindowState == WindowState.Fullscreen ? "enabled" : "disabled"), font, Color.White, RectangleF.Empty); printer.End(); diff --git a/Source/Examples/Tutorial/Fonts.cs b/Source/Examples/Tutorial/Fonts.cs index e675012d..02f3608b 100644 --- a/Source/Examples/Tutorial/Fonts.cs +++ b/Source/Examples/Tutorial/Fonts.cs @@ -96,7 +96,7 @@ namespace Examples.Tutorial /// public override void OnLoad(EventArgs e) { - GL.ClearColor(Color.SteelBlue); + GL.ClearColor(Color.MidnightBlue); } #endregion diff --git a/Source/Examples/Tutorial/T01_Simple_Window.cs b/Source/Examples/Tutorial/T01_Simple_Window.cs index bbd100b3..94d7df22 100644 --- a/Source/Examples/Tutorial/T01_Simple_Window.cs +++ b/Source/Examples/Tutorial/T01_Simple_Window.cs @@ -58,7 +58,7 @@ namespace Examples.Tutorial /// Not used. public override void OnLoad(EventArgs e) { - GL.ClearColor(Color.SteelBlue); + GL.ClearColor(Color.MidnightBlue); } #endregion @@ -110,7 +110,7 @@ namespace Examples.Tutorial GL.Begin(BeginMode.Triangles); - GL.Color3(Color.LightSteelBlue); + GL.Color3(Color.MidnightBlue); GL.Vertex2(-1.0f, 1.0f); GL.Color3(Color.SpringGreen); GL.Vertex2(0.0f, -1.0f); diff --git a/Source/Examples/Tutorial/T03_Immediate_Mode_Cube.cs b/Source/Examples/Tutorial/T03_Immediate_Mode_Cube.cs index ae6c9e46..bba719bb 100644 --- a/Source/Examples/Tutorial/T03_Immediate_Mode_Cube.cs +++ b/Source/Examples/Tutorial/T03_Immediate_Mode_Cube.cs @@ -14,7 +14,7 @@ using System.Windows.Forms; using System.Threading; using System.Drawing; -using OpenTK; +using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; @@ -48,7 +48,7 @@ namespace Examples.Tutorial { base.OnLoad(e); - GL.ClearColor(Color.SteelBlue); + GL.ClearColor(Color.MidnightBlue); GL.Enable(EnableCap.DepthTest); } diff --git a/Source/Examples/Tutorial/T07_Display_Lists_Flower.cs b/Source/Examples/Tutorial/T07_Display_Lists_Flower.cs index 178de914..dcce0415 100644 --- a/Source/Examples/Tutorial/T07_Display_Lists_Flower.cs +++ b/Source/Examples/Tutorial/T07_Display_Lists_Flower.cs @@ -45,7 +45,7 @@ namespace Examples.Tutorial public override void OnLoad(EventArgs e) { - GL.ClearColor(Color.SteelBlue); + GL.ClearColor(Color.MidnightBlue); GL.Enable(EnableCap.DepthTest); GL.MatrixMode(MatrixMode.Modelview); diff --git a/Source/Examples/Tutorial/T10_GLSL_Cube.cs b/Source/Examples/Tutorial/T10_GLSL_Cube.cs index 0b36314c..06c94beb 100644 --- a/Source/Examples/Tutorial/T10_GLSL_Cube.cs +++ b/Source/Examples/Tutorial/T10_GLSL_Cube.cs @@ -68,7 +68,7 @@ namespace Examples.Tutorial this.Exit(); } - GL.ClearColor(Color.SteelBlue); + GL.ClearColor(Color.MidnightBlue); GL.Enable(EnableCap.DepthTest); CreateVBO(); diff --git a/Source/Examples/Tutorial/Textures.cs b/Source/Examples/Tutorial/Textures.cs index 45674714..3c3a1586 100644 --- a/Source/Examples/Tutorial/Textures.cs +++ b/Source/Examples/Tutorial/Textures.cs @@ -39,7 +39,7 @@ namespace Examples.Tutorial /// Not used. public override void OnLoad(EventArgs e) { - GL.ClearColor(Color.SteelBlue); + GL.ClearColor(Color.MidnightBlue); GL.Enable(EnableCap.Texture2D); GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); diff --git a/Source/Examples/WinForms/W02_Immediate_Mode_Cube.cs b/Source/Examples/WinForms/W02_Immediate_Mode_Cube.cs index da4ecd22..04673145 100644 --- a/Source/Examples/WinForms/W02_Immediate_Mode_Cube.cs +++ b/Source/Examples/WinForms/W02_Immediate_Mode_Cube.cs @@ -53,7 +53,7 @@ namespace Examples.WinForms GL.GetString(StringName.Renderer) + " " + GL.GetString(StringName.Version); - GL.ClearColor(Color.SteelBlue); + GL.ClearColor(Color.MidnightBlue); GL.Enable(EnableCap.DepthTest); Application.Idle += Application_Idle;