diff --git a/Source/Compatibility/Fonts/DisplayListTextHandle.cs b/Source/Compatibility/Fonts/DisplayListTextHandle.cs
new file mode 100644
index 00000000..44395d58
--- /dev/null
+++ b/Source/Compatibility/Fonts/DisplayListTextHandle.cs
@@ -0,0 +1,37 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using OpenTK.Graphics.OpenGL;
+
+namespace OpenTK.Graphics
+{
+ [Obsolete()]
+ class DisplayListTextHandle : TextHandle
+ {
+ public DisplayListTextHandle(int handle) : base(handle) { }
+
+ public override string ToString()
+ {
+ return String.Format("TextHandle (display list): {0}", Handle);
+ }
+
+ protected override void Dispose(bool manual)
+ {
+ if (!disposed)
+ {
+ if (manual)
+ {
+ GL.DeleteLists(Handle, 1);
+ }
+ disposed = true;
+ }
+ }
+ }
+}
diff --git a/Source/Compatibility/Fonts/DisplayListTextPrinter.cs b/Source/Compatibility/Fonts/DisplayListTextPrinter.cs
new file mode 100644
index 00000000..2db546e2
--- /dev/null
+++ b/Source/Compatibility/Fonts/DisplayListTextPrinter.cs
@@ -0,0 +1,57 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using OpenTK.Graphics.OpenGL;
+
+namespace OpenTK.Graphics
+{
+ ///
+ /// Provides text printing through OpenGL 1.1 Display Lists.
+ ///
+ [Obsolete()]
+ class DisplayListTextPrinter : ITextPrinterImplementation
+ {
+ #region IPrinter Members
+
+ public TextHandle Load(Vector2[] vertices, ushort[] indices, int index_count)
+ {
+ DisplayListTextHandle handle = new DisplayListTextHandle(GL.GenLists(1));
+
+ GL.NewList(handle.Handle, ListMode.Compile);
+
+ this.Draw(vertices, indices, index_count);
+
+ GL.EndList();
+
+ return handle;
+ }
+
+ public void Draw(TextHandle handle)
+ {
+ GL.CallList(handle.Handle);
+ }
+
+ public void Draw(Vector2[] vertices, ushort[] indices, int index_count)
+ {
+ GL.Begin(BeginMode.Triangles);
+
+ for (int i = 0; i < index_count; i++)
+ //foreach (ushort index in indices)
+ {
+ GL.TexCoord2(vertices[indices[i] + 1]);
+ GL.Vertex2(vertices[indices[i]]);
+ }
+
+ GL.End();
+ }
+
+ #endregion
+ }
+}
diff --git a/Source/Compatibility/Fonts/Glyph.cs b/Source/Compatibility/Fonts/Glyph.cs
new file mode 100644
index 00000000..8cbb83c4
--- /dev/null
+++ b/Source/Compatibility/Fonts/Glyph.cs
@@ -0,0 +1,176 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+
+namespace OpenTK.Graphics
+{
+ using Graphics = System.Drawing.Graphics;
+
+ ///
+ /// Represents a single character of a specific Font.
+ ///
+ [Obsolete]
+ struct Glyph : IPackable
+ {
+ char character;
+ Font font;
+ SizeF size;
+
+ #region --- Constructors ---
+
+ // Constructs a new Glyph that represents the given character and Font.
+ public Glyph(char c, Font f, SizeF s)
+ {
+ if (f == null)
+ throw new ArgumentNullException("f", "You must specify a valid font");
+ character = c;
+ font = f;
+ size = s;
+ }
+
+ #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}, ({5}, {6})", Character, Font.Name, font.Style, font.Size, font.Unit, Width, Height);
+ }
+
+ #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() ^ 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 ---
+
+ ///
+ /// Gets an integer representing the width of the Glyph in pixels.
+ ///
+ public int Width
+ {
+ get
+ {
+ return (int)System.Math.Ceiling(size.Width);
+ }
+ }
+
+ ///
+ /// Gets an integer representing the height of the Glyph in pixels.
+ ///
+ public int Height
+ {
+ get
+ {
+ return (int)System.Math.Ceiling(size.Height);
+ }
+ }
+
+ #endregion
+
+ #region --- IEquatable Members ---
+
+ ///
+ /// Compares the current Glyph with the given Glyph.
+ ///
+ /// The Glyph to compare to.
+ /// 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 && Size == other.Size;
+ }
+
+ #endregion
+ }
+}
diff --git a/Source/Compatibility/Fonts/IFont.cs b/Source/Compatibility/Fonts/IFont.cs
new file mode 100644
index 00000000..d73ddbb9
--- /dev/null
+++ b/Source/Compatibility/Fonts/IFont.cs
@@ -0,0 +1,21 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+
+namespace OpenTK.Graphics
+{
+ [Obsolete]
+ public interface IFont : IDisposable
+ {
+ void LoadGlyphs(string glyphs);
+ float Height { get; }
+ void MeasureString(string str, out float width, out float height);
+ }
+}
diff --git a/Source/Compatibility/Fonts/IPrinterImplementation.cs b/Source/Compatibility/Fonts/IPrinterImplementation.cs
new file mode 100644
index 00000000..08218bf9
--- /dev/null
+++ b/Source/Compatibility/Fonts/IPrinterImplementation.cs
@@ -0,0 +1,45 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+
+namespace OpenTK.Graphics
+{
+ ///
+ /// Defines the interface for TextPrinter implementations.
+ ///
+ [Obsolete("Use ITextOutputProvider instead")]
+ public interface ITextPrinterImplementation
+ {
+ ///
+ /// Caches a text fragment for future use.
+ ///
+ /// The vertex array for the text fragment.
+ /// The index array for the text fragment. Please use the indexCount parameter
+ /// instead of indices.Count, as the indices array may be larger than necessary for performance reasons.
+ /// The actual number of indices in the text fragment.
+ /// A TextHandle that can be used to draw the text fragment.
+ TextHandle Load(Vector2[] vertices, ushort[] indices, int indexCount);
+
+ ///
+ /// Draws the specified cached text fragment.
+ ///
+ /// The TextHandle corresponding to the desired text fragment.
+ void Draw(TextHandle handle);
+
+ ///
+ /// Draws a text fragment, without caching.
+ ///
+ /// The vertex array for the text fragment.
+ /// The index array for the text fragment. Please use the indexCount parameter
+ /// instead of indices.Count, as the indices array may be larger than necessary for performance reasons.
+ /// The actual number of indices in the text fragment.
+ void Draw(Vector2[] vertices, ushort[] indices, int indexCount);
+ }
+}
diff --git a/Source/Compatibility/Fonts/TextHandle.cs b/Source/Compatibility/Fonts/TextHandle.cs
new file mode 100644
index 00000000..10cedf35
--- /dev/null
+++ b/Source/Compatibility/Fonts/TextHandle.cs
@@ -0,0 +1,88 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace OpenTK.Graphics
+{
+ ///
+ /// Represents a handle to cached text.
+ ///
+ [Obsolete("Use TextPrinter.Print instead")]
+ public class TextHandle : IDisposable
+ {
+ internal string Text;
+ internal System.Drawing.Font GdiPFont;
+
+ ///
+ /// Constructs a new TextHandle,
+ ///
+ ///
+ 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;
+
+ ///
+ /// Gets the handle of the cached text run. Call the OpenTK.Graphics.ITextPrinter.Draw() method
+ /// to draw the text represented by this TextHandle.
+ ///
+ public int Handle
+ {
+ get { return handle; }
+ protected set { handle = value; }
+ }
+
+ ///
+ /// Gets the TextureFont used for this text run.
+ ///
+ public TextureFont Font
+ {
+ get { return font; }
+ internal set { font = value; }
+ }
+
+ #region public override string ToString()
+
+ ///
+ /// Returns a System.String that represents the current TextHandle.
+ ///
+ /// a System.String that descibes the current TextHandle.
+ public override string ToString()
+ {
+ return String.Format("TextHandle: {0}", Handle);
+ }
+
+ #endregion
+
+ #region --- IDisposable Members ---
+
+ ///
+ /// Frees the resource consumed by the TextHandle.
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ protected virtual void Dispose(bool manual) { }
+ ~TextHandle() { this.Dispose(false); }
+
+ #endregion
+ }
+}
diff --git a/Source/Compatibility/Fonts/TextureFont.cs b/Source/Compatibility/Fonts/TextureFont.cs
new file mode 100644
index 00000000..b8d434f8
--- /dev/null
+++ b/Source/Compatibility/Fonts/TextureFont.cs
@@ -0,0 +1,563 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing.Text;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+
+using OpenTK.Graphics.OpenGL;
+using OpenTK.Platform;
+
+namespace OpenTK.Graphics
+{
+ using Graphics = System.Drawing.Graphics;
+ using PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat;
+ using System.Text.RegularExpressions;
+
+ [Obsolete("Use System.Drawing.Font instead")]
+ public class TextureFont : IFont
+ {
+ internal Font font;
+ Dictionary loaded_glyphs = new Dictionary(64);
+
+ Bitmap bmp;
+ Graphics gfx;
+ // TODO: We need to be able to use multiple font sheets.
+ static int texture;
+ static TexturePacker pack;
+ static int texture_width, texture_height;
+ static readonly StringFormat default_string_format = StringFormat.GenericTypographic; // Check the constructor, too, for additional flags.
+ static readonly StringFormat load_glyph_string_format = StringFormat.GenericDefault;
+ static SizeF maximum_graphics_size;
+
+ int[] data = new int[256]; // Used to upload the glyph buffer to the OpenGL texture.
+
+ object upload_lock = new object();
+
+ static readonly char[] newline_characters = new char[] { '\n', '\r' };
+
+ #region --- Constructor ---
+
+ ///
+ /// Constructs a new TextureFont, using the specified System.Drawing.Font.
+ ///
+ /// The System.Drawing.Font to use.
+ public TextureFont(Font font)
+ {
+ if (font == null)
+ throw new ArgumentNullException("font", "Argument to TextureFont constructor cannot be null.");
+
+ this.font = font;
+
+ bmp = new Bitmap(font.Height * 2, font.Height * 2);
+ gfx = Graphics.FromImage(bmp);
+ maximum_graphics_size = gfx.ClipBounds.Size;
+
+ // Adjust font rendering mode. Small sizes look blurry without gridfitting, so turn
+ // that on. Increasing contrast also seems to help.
+ if (font.Size <= 18.0f)
+ {
+ gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
+ //gfx.TextContrast = 11;
+ }
+ else
+ {
+ gfx.TextRenderingHint = TextRenderingHint.AntiAlias;
+ //gfx.TextContrast = 0;
+ }
+
+ default_string_format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
+ }
+
+ ///
+ /// Constructs a new TextureFont, using the specified parameters.
+ ///
+ /// The System.Drawing.FontFamily to use for the typeface.
+ /// The em size to use for the typeface.
+ public TextureFont(FontFamily family, float emSize)
+ : this(new Font(family, emSize))
+ { }
+
+ ///
+ /// Constructs a new TextureFont, using the specified parameters.
+ ///
+ /// The System.Drawing.FontFamily to use for the typeface.
+ /// The em size to use for the typeface.
+ /// The style to use for the typeface.
+ public TextureFont(FontFamily family, float emSize, FontStyle style)
+ : this(new Font(family, emSize, style))
+ { }
+
+ #endregion
+
+ #region --- Public Methods ---
+
+ #region public void LoadGlyphs(string glyphs)
+
+ ///
+ /// Prepares the specified glyphs for rendering.
+ ///
+ /// The glyphs to prepare for rendering.
+ public void LoadGlyphs(string glyphs)
+ {
+ RectangleF rect = new RectangleF();
+ foreach (char c in glyphs)
+ {
+ if (Char.IsWhiteSpace(c))
+ continue;
+
+ try
+ {
+ if (!loaded_glyphs.ContainsKey(c))
+ LoadGlyph(c, out rect);
+ }
+ catch (Exception e)
+ {
+ Debug.Print(e.ToString());
+ throw;
+ }
+ }
+ }
+
+ #endregion
+
+ #region public void LoadGlyph(char glyph)
+
+ ///
+ /// Prepares the specified glyph for rendering.
+ ///
+ /// The glyph to prepare for rendering.
+ public void LoadGlyph(char glyph)
+ {
+ RectangleF rect = new RectangleF();
+ if (!loaded_glyphs.ContainsKey(glyph))
+ LoadGlyph(glyph, out rect);
+ }
+
+ #endregion
+
+ #region public bool GlyphData(char glyph, out float width, out float height, out RectangleF textureRectangle, out int texture)
+
+ ///
+ /// Returns the characteristics of a loaded glyph.
+ ///
+ /// The character corresponding to this glyph.
+ /// The width of this glyph.
+ /// The height of this glyph (line spacing).
+ /// The bounding box of the texture buffer of this glyph.
+ /// The handle to the texture that contains this glyph.
+ /// True if the glyph has been loaded, false otherwise.
+ ///
+ public bool GlyphData(char glyph, out float width, out float height, out RectangleF textureRectangle, out int texture)
+ {
+ if (loaded_glyphs.TryGetValue(glyph, out textureRectangle))
+ {
+ width = textureRectangle.Width * texture_width;
+ height = textureRectangle.Height * texture_height;
+ texture = TextureFont.texture;
+ return true;
+ }
+ width = height = texture = 0;
+ return false;
+ }
+
+ #endregion
+
+ #region public float Height
+
+ ///
+ /// Gets a float indicating the default line spacing of this font.
+ ///
+ public float Height
+ {
+ get { return font.Height; }
+ }
+
+ #endregion
+
+ #region public float Width
+
+ ///
+ /// Gets a float indicating the default size of this font, in points.
+ ///
+ public float Width
+ {
+ get { return font.SizeInPoints; }
+ }
+
+ #endregion
+
+ #region public void MeasureString(string str, out float width, out float height, bool accountForOverhangs)
+
+ ///
+ /// Measures the width of the specified string.
+ ///
+ /// The string to measure.
+ /// The measured width.
+ /// The measured height.
+ /// If true, adds space to account for glyph overhangs. Set to true if you wish to measure a complete string. Set to false if you wish to perform layout on adjacent strings.
+ [Obsolete("Returns invalid results - use MeasureText() instead")]
+ public void MeasureString(string str, out float width, out float height, bool accountForOverhangs)
+ {
+ System.Drawing.StringFormat format = accountForOverhangs ? System.Drawing.StringFormat.GenericDefault : System.Drawing.StringFormat.GenericTypographic;
+
+ System.Drawing.SizeF size = gfx.MeasureString(str, font, 16384, format);
+ height = size.Height;
+ width = size.Width;
+ }
+
+ #endregion
+
+ #region public void MeasureString(string str, out float width, out float height)
+
+ ///
+ /// Measures the width of the specified string.
+ ///
+ /// The string to measure.
+ /// The measured width.
+ /// The measured height.
+ ///
+ [Obsolete("Returns invalid results - use MeasureText() instead")]
+ public void MeasureString(string str, out float width, out float height)
+ {
+ MeasureString(str, out width, out height, true);
+ }
+
+ #endregion
+
+ #region public RectangleF MeasureText(string text)
+
+ ///
+ /// Calculates size information for the specified text.
+ ///
+ /// The string to measure.
+ /// A RectangleF containing the bounding box for the specified text.
+ public RectangleF MeasureText(string text)
+ {
+ return MeasureText(text, SizeF.Empty, default_string_format, null);
+ }
+
+ #endregion
+
+ #region public RectangleF MeasureText(string text, SizeF bounds)
+
+ ///
+ /// Calculates size information for the specified text.
+ ///
+ /// The string to measure.
+ /// A SizeF structure containing the maximum desired width and height of the text. Default is SizeF.Empty.
+ /// A RectangleF containing the bounding box for the specified text.
+ public RectangleF MeasureText(string text, SizeF bounds)
+ {
+ return MeasureText(text, bounds, default_string_format, null);
+ }
+
+ #endregion
+
+ #region public RectangleF MeasureText(string text, SizeF bounds, StringFormat format)
+
+ ///
+ /// Calculates size information for the specified text.
+ ///
+ /// The string to measure.
+ /// A SizeF structure containing the maximum desired width and height of the text. Pass SizeF.Empty to disable wrapping calculations. A width or height of 0 disables the relevant calculation.
+ /// A StringFormat object which specifies the measurement format of the string. Pass null to use the default StringFormat (StringFormat.GenericTypographic).
+ /// A RectangleF containing the bounding box for the specified text.
+ public RectangleF MeasureText(string text, SizeF bounds, StringFormat format)
+ {
+ return MeasureText(text, bounds, format, null);
+ }
+
+ #endregion
+
+ #region public RectangleF MeasureText(string text, SizeF bounds, StringFormat format, IList ranges)
+
+ IntPtr[] regions = new IntPtr[GdiPlus.MaxMeasurableCharacterRanges];
+ CharacterRange[] characterRanges = new CharacterRange[GdiPlus.MaxMeasurableCharacterRanges];
+
+ ///
+ /// Calculates size information for the specified text.
+ ///
+ /// The string to measure.
+ /// A SizeF structure containing the maximum desired width and height of the text. Pass SizeF.Empty to disable wrapping calculations. A width or height of 0 disables the relevant calculation.
+ /// A StringFormat object which specifies the measurement format of the string. Pass null to use the default StringFormat (StringFormat.GenericDefault).
+ /// Fills the specified IList of RectangleF structures with position information for individual characters. If this argument is null, these calculations are skipped.
+ /// A RectangleF containing the bounding box for the specified text.
+ public RectangleF MeasureText(string text, SizeF bounds, StringFormat format, List ranges)
+ {
+ if (String.IsNullOrEmpty(text))
+ return RectangleF.Empty;
+
+ if (bounds == SizeF.Empty)
+ bounds = maximum_graphics_size;
+
+ if (format == null)
+ format = default_string_format;
+
+ // TODO: What should we do in this case?
+ if (ranges == null)
+ ranges = new List();
+
+ ranges.Clear();
+
+ PointF origin = PointF.Empty;
+ SizeF size = SizeF.Empty;
+
+ IntPtr native_graphics = GdiPlus.GetNativeGraphics(gfx);
+ IntPtr native_font = GdiPlus.GetNativeFont(font);
+ IntPtr native_string_format = GdiPlus.GetNativeStringFormat(format);
+
+ RectangleF layoutRect = new RectangleF(PointF.Empty, bounds);
+
+ 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 = text.Replace("\r", String.Empty).Split(newline_characters);
+ foreach (string s in lines)
+ {
+ ranges.AddRange(GetCharExtents(
+ s, height, 0, s.Length, layoutRect,
+ native_graphics, native_font, native_string_format));
+ height += font.Height;
+ }
+ }
+
+ return new RectangleF(ranges[0].X, ranges[0].Y, ranges[ranges.Count - 1].Right, ranges[ranges.Count - 1].Bottom);
+ }
+
+ #endregion
+
+ #endregion
+
+ #region --- Private Methods ---
+
+ #region private void PrepareTexturePacker()
+
+ ///
+ /// Calculates the optimal size for the font texture and TexturePacker, and creates both.
+ ///
+ private void PrepareTexturePacker()
+ {
+ // Calculate the size of the texture packer. We want a power-of-two size
+ // that is less than 1024 (supported in Geforce256-era cards), but large
+ // enough to hold at least 256 (16*16) font glyphs.
+ // TODO: Find the actual card limits, maybe?
+ int size = (int)(font.Size * 16);
+ size = (int)System.Math.Pow(2.0, System.Math.Ceiling(System.Math.Log((double)size, 2.0)));
+ if (size > 1024)
+ size = 1024;
+
+ texture_width = size;
+ texture_height = size;
+ pack = new TexturePacker(texture_width, texture_height);
+
+ GL.GenTextures(1, out texture);
+ GL.BindTexture(TextureTarget.Texture2D, texture);
+ 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, texture_width, texture_height, 0,
+ OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
+ }
+
+ #endregion
+
+ #region private void LoadGlyph(char c, out RectangleF rectangle)
+
+ // Adds the specified caharacter to the texture packer.
+ private void LoadGlyph(char c, out RectangleF rectangle)
+ {
+ if (pack == null)
+ PrepareTexturePacker();
+
+ RectangleF glyph_rect = MeasureText(c.ToString(), SizeF.Empty, load_glyph_string_format);
+ SizeF glyph_size = new SizeF(glyph_rect.Right, glyph_rect.Bottom); // We need to do this, since the origin might not be (0, 0)
+ Glyph g = new Glyph(c, font, glyph_size);
+ Rectangle rect;
+
+ try
+ {
+ pack.Add(g, out rect);
+ }
+ catch (InvalidOperationException expt)
+ {
+ // TODO: The TexturePacker is full, create a new font sheet.
+ Trace.WriteLine(expt);
+ throw;
+ }
+
+ GL.BindTexture(TextureTarget.Texture2D, texture);
+
+ gfx.Clear(System.Drawing.Color.Transparent);
+ gfx.DrawString(g.Character.ToString(), g.Font, System.Drawing.Brushes.White, 0.0f, 0.0f, default_string_format);
+
+ BitmapData bitmap_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly,
+ System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+
+ GL.PushClientAttrib(ClientAttribMask.ClientPixelStoreBit);
+ try
+ {
+ GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1.0f);
+ GL.PixelStore(PixelStoreParameter.UnpackRowLength, bmp.Width);
+ GL.TexSubImage2D(TextureTarget.Texture2D, 0, (int)rect.Left, (int)rect.Top,
+ rect.Width, rect.Height,
+ OpenTK.Graphics.PixelFormat.Rgba,
+ PixelType.UnsignedByte, bitmap_data.Scan0);
+ }
+ finally
+ {
+ GL.PopClientAttrib();
+ }
+
+ bmp.UnlockBits(bitmap_data);
+
+ rectangle = RectangleF.FromLTRB(
+ rect.Left / (float)texture_width,
+ rect.Top / (float)texture_height,
+ rect.Right / (float)texture_width,
+ rect.Bottom / (float)texture_height);
+
+ loaded_glyphs.Add(g.Character, rectangle);
+ }
+
+ #endregion
+
+ #region GetCharExtents
+
+ // Gets the bounds of each character in a line of text.
+ // The line is processed in blocks of 32 characters (GdiPlus.MaxMeasurableCharacterRanges).
+ IEnumerable GetCharExtents(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
+
+ #endregion
+
+ #region --- Internal Methods ---
+
+ #region internal int Texture
+
+ ///
+ /// Gets the handle to the texture were this font resides.
+ ///
+ internal int Texture
+ {
+ get { return TextureFont.texture; }
+ }
+
+ #endregion
+
+ #endregion
+
+ #region --- IDisposable Members ---
+
+ bool disposed;
+
+ ///
+ /// Releases all resources used by this OpenTK.Graphics.TextureFont.
+ ///
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ Dispose(true);
+ }
+
+ private void Dispose(bool manual)
+ {
+ if (!disposed)
+ {
+ pack = null;
+ if (manual)
+ {
+ GL.DeleteTextures(1, ref texture);
+ font.Dispose();
+ gfx.Dispose();
+ }
+
+ disposed = true;
+ }
+ }
+
+ ///
+ /// Finalizes this TextureFont.
+ ///
+ ~TextureFont()
+ {
+ Dispose(false);
+ }
+
+ #endregion
+ }
+}
diff --git a/Source/Compatibility/Fonts/VboTextPrinter.cs b/Source/Compatibility/Fonts/VboTextPrinter.cs
new file mode 100644
index 00000000..15333ddb
--- /dev/null
+++ b/Source/Compatibility/Fonts/VboTextPrinter.cs
@@ -0,0 +1,104 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+
+using OpenTK.Graphics.OpenGL;
+
+namespace OpenTK.Graphics
+{
+ ///
+ /// Provides text printing through OpenGL 1.5 vertex buffer objects.
+ ///
+ [Obsolete]
+ class VboTextPrinter : ITextPrinterImplementation
+ {
+ static int allocated_handles;
+ static int vector2_size = Marshal.SizeOf(new Vector2());
+
+ #region --- IPrinter Members ---
+
+ public TextHandle Load(Vector2[] vertices, ushort[] indices, int index_count)
+ {
+ VboTextHandle handle = new VboTextHandle(++allocated_handles);
+
+ GL.GenBuffers(1, out handle.vbo_id);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, handle.vbo_id);
+ GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * vector2_size), vertices,
+ BufferUsageHint.StaticDraw);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
+
+ GL.GenBuffers(1, out handle.ebo_id);
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle.ebo_id);
+ GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Length * sizeof(ushort)), indices,
+ BufferUsageHint.StaticDraw);
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
+
+ handle.element_count = indices.Length;
+ return handle;
+ }
+
+ public void Draw(TextHandle handle)
+ {
+ VboTextHandle vbo = (VboTextHandle)handle;
+
+ //GL.PushClientAttrib(ClientAttribMask.ClientVertexArrayBit);
+
+ //GL.EnableClientState(EnableCap.TextureCoordArray);
+ GL.EnableClientState(EnableCap.VertexArray);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, vbo.vbo_id);
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, vbo.ebo_id);
+
+ GL.TexCoordPointer(2, TexCoordPointerType.Float, vector2_size, (IntPtr)vector2_size);
+ GL.VertexPointer(2, VertexPointerType.Float, vector2_size, IntPtr.Zero);
+
+ GL.DrawElements(BeginMode.Triangles, vbo.element_count, DrawElementsType.UnsignedShort, IntPtr.Zero);
+ //GL.DrawArrays(BeginMode.LineLoop, 0, vbo.element_count);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
+
+ GL.DisableClientState(EnableCap.VertexArray);
+ //GL.DisableClientState(EnableCap.TextureCoordArray);
+
+ //GL.PopClientAttrib();
+ }
+
+ public void Draw(Vector2[] vertices, ushort[] indices, int index_count)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+
+ #region class VboTextHandle : TextHandle
+
+ ///
+ /// Contains the necessary information to print text through the VboTextPrinter implementation.
+ ///
+ [Obsolete]
+ class VboTextHandle : TextHandle
+ {
+ public VboTextHandle(int handle) : base(handle) { }
+
+ internal int vbo_id; // vertex buffer object id.
+ internal int ebo_id; // index buffer object id.
+ internal int element_count; // Number of elements in the ebo.
+
+ public override string ToString()
+ {
+ return String.Format("TextHandle (vbo): {0} ({1} element(s), vbo id: {2}, ebo id: {3}",
+ Handle, element_count / 6, vbo_id, ebo_id);
+ }
+ }
+
+ #endregion
+}
diff --git a/Source/Compatibility/IPackable.cs b/Source/Compatibility/IPackable.cs
new file mode 100644
index 00000000..15b04931
--- /dev/null
+++ b/Source/Compatibility/IPackable.cs
@@ -0,0 +1,22 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace OpenTK
+{
+ ///
+ /// Represents an item that can be packed with the TexturePacker.
+ ///
+ /// The type of the packable item.
+ interface IPackable : IEquatable
+ {
+ int Width { get; }
+ int Height { get; }
+ }
+}
diff --git a/Source/Compatibility/IPoolable.cs b/Source/Compatibility/IPoolable.cs
new file mode 100644
index 00000000..68d83f36
--- /dev/null
+++ b/Source/Compatibility/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/Compatibility/ObjectPool.cs b/Source/Compatibility/ObjectPool.cs
new file mode 100644
index 00000000..3ad38112
--- /dev/null
+++ b/Source/Compatibility/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);
+ }
+ }
+}
diff --git a/Source/OpenTK/Platform/GdiPlus.cs b/Source/Compatibility/Platform/GdiPlus.cs
similarity index 100%
rename from Source/OpenTK/Platform/GdiPlus.cs
rename to Source/Compatibility/Platform/GdiPlus.cs
diff --git a/Source/OpenTK/Platform/IGdiPlusInternals.cs b/Source/Compatibility/Platform/IGdiPlusInternals.cs
similarity index 100%
rename from Source/OpenTK/Platform/IGdiPlusInternals.cs
rename to Source/Compatibility/Platform/IGdiPlusInternals.cs
diff --git a/Source/OpenTK/Platform/Windows/WinGdiPlusInternals.cs b/Source/Compatibility/Platform/Windows/WinGdiPlusInternals.cs
similarity index 100%
rename from Source/OpenTK/Platform/Windows/WinGdiPlusInternals.cs
rename to Source/Compatibility/Platform/Windows/WinGdiPlusInternals.cs
diff --git a/Source/OpenTK/Platform/X11/X11GdiPlusInternals.cs b/Source/Compatibility/Platform/X11/X11GdiPlusInternals.cs
similarity index 100%
rename from Source/OpenTK/Platform/X11/X11GdiPlusInternals.cs
rename to Source/Compatibility/Platform/X11/X11GdiPlusInternals.cs
diff --git a/Source/Compatibility/TexturePacker.cs b/Source/Compatibility/TexturePacker.cs
new file mode 100644
index 00000000..41be16a6
--- /dev/null
+++ b/Source/Compatibility/TexturePacker.cs
@@ -0,0 +1,195 @@
+#region --- License ---
+/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
+ * See license.txt for license info
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using System.Drawing.Imaging;
+
+namespace OpenTK
+{
+ class TexturePacker where T : IPackable
+ {
+ Node root;
+
+ #region --- Constructors ---
+
+ public TexturePacker(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.Rect = new Rectangle(0, 0, width, width);
+ }
+
+ #endregion
+
+ #region --- Public Methods ---
+
+ #region public Rectangle Add(T item)
+
+ // Packs the given item into the free space of the TexturePacker. Returns the Rectangle of the packed item.
+ public void Add(T item, out Rectangle rect)
+ {
+ if (item.Width > root.Rect.Width || item.Height > root.Rect.Height)
+ throw new InvalidOperationException("The item is too large for this TexturePacker");
+
+ Node node;
+ //if (!items.ContainsKey(item))
+ {
+ node = root.Insert(item);
+
+ // Tree is full and insertion failed:
+ if (node == null)
+ throw new TexturePackerFullException();
+
+ //items.Add(item, node);
+ rect = node.Rect;
+ }
+ //throw new ArgumentException("The item already exists in the TexturePacker.", "item");
+ }
+
+ #endregion
+
+ #region public void Clear()
+
+ ///
+ /// Discards all packed items.
+ ///
+ public void Clear()
+ {
+ //items.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;
+ int use_count;
+
+ public Rectangle Rect { 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 public Node Insert(T item)
+
+ public Node Insert(T item)
+ {
+ if (!this.Leaf)
+ {
+ // Recurse towards left child, and if that fails, towards the right.
+ Node new_node = left.Insert(item);
+ return new_node ?? right.Insert(item);
+ }
+ else
+ {
+ // We have recursed to a leaf.
+
+ // If it is not empty go back.
+ if (use_count != 0)
+ return null;
+
+ // If this leaf is too small go back.
+ if (rect.Width < item.Width || rect.Height < item.Height)
+ return null;
+
+ // If this leaf is the right size, insert here.
+ if (rect.Width == item.Width && rect.Height == item.Height)
+ {
+ use_count = 1;
+ 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 - item.Width + 1;
+ int dh = this.rect.Height - item.Height + 1;
+
+ if (dw > dh)
+ {
+ left.rect = new Rectangle(rect.Left, rect.Top, item.Width, rect.Height);
+ right.rect = new Rectangle(rect.Left + item.Width, rect.Top, rect.Width - item.Width, rect.Height);
+ }
+ else
+ {
+ left.rect = new Rectangle(rect.Left, rect.Top, rect.Width, item.Height);
+ right.rect = new Rectangle(rect.Left, rect.Top + item.Height, rect.Width, rect.Height - item.Height);
+ }
+
+ return left.Insert(item);
+ }
+ }
+
+ #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/Texture2D.cs b/Source/Utilities/Graphics/Texture2D.cs
index 5b46df5e..1d85c742 100644
--- a/Source/Utilities/Graphics/Texture2D.cs
+++ b/Source/Utilities/Graphics/Texture2D.cs
@@ -31,7 +31,6 @@ using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
-using OpenTK.Graphics.OpenGL;
namespace OpenTK.Graphics
{
@@ -137,7 +136,7 @@ namespace OpenTK.Graphics
GL.TexSubImage2D(TextureTarget.Texture2D, mipLevel,
target.Left, target.Top,
target.Width, target.Height,
- OpenTK.Graphics.OpenGL.PixelFormat.Bgra,
+ OpenTK.Graphics.PixelFormat.Bgra,
PixelType.UnsignedByte, data.Scan0);
}
finally
@@ -159,7 +158,7 @@ namespace OpenTK.Graphics
TextureRegion2D region = new TextureRegion2D(rect);
- GL.GetTexImage(TextureTarget.Texture2D, mipLevel, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, region.Data);
+ GL.GetTexImage(TextureTarget.Texture2D, mipLevel, OpenTK.Graphics.PixelFormat.Bgra, PixelType.UnsignedByte, region.Data);
return region;
}
@@ -223,7 +222,7 @@ namespace OpenTK.Graphics
SetDefaultTextureParameters(id);
GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat, Width, Height, 0,
- OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
+ OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
return id;
}