diff --git a/Source/Compatibility/Graphics/AlphaTexture2D.cs b/Source/Compatibility/Graphics/AlphaTexture2D.cs new file mode 100644 index 00000000..4ab43043 --- /dev/null +++ b/Source/Compatibility/Graphics/AlphaTexture2D.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; +using System.Drawing.Imaging; +using OpenTK.Graphics.OpenGL; + +namespace OpenTK.Graphics +{ + /// + /// Encapsulates an OpenGL texture. + /// + class AlphaTexture2D : Texture2D + { + #region Constructors + + /// + /// Constructs a new Texture. + /// + public AlphaTexture2D(int width, int height) + : base(width, height) + { } + + #endregion + + #region Protected Members + + protected override PixelInternalFormat InternalFormat + { + get { return PixelInternalFormat.Alpha; } + } + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/GraphicsResourceException.cs b/Source/Compatibility/Graphics/GraphicsResourceException.cs new file mode 100644 index 00000000..5f84589b --- /dev/null +++ b/Source/Compatibility/Graphics/GraphicsResourceException.cs @@ -0,0 +1,44 @@ +#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; + +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/Compatibility/Graphics/IGraphicsResource.cs b/Source/Compatibility/Graphics/IGraphicsResource.cs new file mode 100644 index 00000000..e6f79d20 --- /dev/null +++ b/Source/Compatibility/Graphics/IGraphicsResource.cs @@ -0,0 +1,49 @@ +#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; + +namespace OpenTK.Graphics +{ + /// + /// Defines a common interface to all OpenGL resources. + /// + interface IGraphicsResource : IDisposable + { + /// + /// Gets the GraphicsContext that owns this resource. + /// + IGraphicsContext Context { get; } + + /// + /// Gets the Id of this IGraphicsResource. + /// + int Id { get; } + } +} diff --git a/Source/Compatibility/Graphics/ITextPrinter.cs b/Source/Compatibility/Graphics/ITextPrinter.cs new file mode 100644 index 00000000..abdcfb56 --- /dev/null +++ b/Source/Compatibility/Graphics/ITextPrinter.cs @@ -0,0 +1,159 @@ +#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 OpenTK.Graphics.Text; + +namespace OpenTK.Graphics +{ + /// + /// Defines the interface for a TextPrinter. + /// + public interface ITextPrinter : IDisposable + { + #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. + /// 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. + /// 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. + /// 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 Begin + + /// + /// Sets up a resolution-dependent orthographic projection. + /// + void Begin(); + + #endregion + + #region End + + /// + /// Restores the projection and modelview matrices to their previous state. + /// + void End(); + + #endregion + + #region Obsolete + + [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); + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/RgbaTexture2D.cs b/Source/Compatibility/Graphics/RgbaTexture2D.cs new file mode 100644 index 00000000..d010348c --- /dev/null +++ b/Source/Compatibility/Graphics/RgbaTexture2D.cs @@ -0,0 +1,46 @@ +#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 OpenTK.Graphics.OpenGL; + +namespace OpenTK.Graphics +{ + class RgbaTexture2D : Texture2D + { + public RgbaTexture2D(int width, int height) + : base(width, height) + { } + + protected override PixelInternalFormat InternalFormat + { + get { return PixelInternalFormat.Rgba; } + } + } +} diff --git a/Source/Compatibility/Graphics/Text/CachedGlyphInfo.cs b/Source/Compatibility/Graphics/Text/CachedGlyphInfo.cs new file mode 100644 index 00000000..f498d332 --- /dev/null +++ b/Source/Compatibility/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); + } + } +} diff --git a/Source/Compatibility/Graphics/Text/GL11TextOutputProvider.cs b/Source/Compatibility/Graphics/Text/GL11TextOutputProvider.cs new file mode 100644 index 00000000..3efeae24 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/GL11TextOutputProvider.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using OpenTK.Graphics.OpenGL; + +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; + } + + #endregion + + #region Protected Members + + protected override void SetBlendFunction() + { + GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // For grayscale + } + + protected override void SetColor(Color color) + { + GL.Color3(color); + } + + protected override TextQuality TextQuality + { + get { return quality; } + } + + protected override GlyphCache Cache + { + get + { + if (cache == null) + { + if (GL.GetString(StringName.Renderer).Contains("ProSavage/Twister")) + cache = new GlyphCache(); + else + cache = new GlyphCache(); + } + return cache; + } + } + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/Text/GL12TextOutputProvider.cs b/Source/Compatibility/Graphics/Text/GL12TextOutputProvider.cs new file mode 100644 index 00000000..e4dbe709 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/GL12TextOutputProvider.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +using OpenTK.Graphics.OpenGL; + +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); + } + + protected override void SetColor(Color color) + { + GL.Color3(Color.White); + GL.BlendColor(color); + } + + protected override TextQuality TextQuality + { + get { return quality; } + } + + protected override GlyphCache Cache + { + get { return cache; } + } + } +} diff --git a/Source/Compatibility/Graphics/Text/GL1TextOutputProvider.cs b/Source/Compatibility/Graphics/Text/GL1TextOutputProvider.cs new file mode 100644 index 00000000..612ef693 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/GL1TextOutputProvider.cs @@ -0,0 +1,339 @@ +#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.Drawing; + +using OpenTK.Graphics.OpenGL; + +namespace OpenTK.Graphics.Text +{ + abstract class GL1TextOutputProvider : ITextOutputProvider + { + #region Fields + + // Triangle lists, sorted by texture. + Dictionary> active_lists = new Dictionary>(); + Queue> inactive_lists = new Queue>(); + + #pragma warning disable 0649 + struct Viewport { public int X, Y, Width, Height; } + #pragma warning restore 0649 + + // Used to save the current state in Begin() and restore it in End() + Stack projection_stack = new Stack(); + Stack modelview_stack = new Stack(); + Stack texture_stack = new Stack(); + Stack viewport_stack = new Stack(); + + // Used as temporary storage when saving / restoring the current state. + Viewport viewport = new Viewport(); + Matrix4 matrix = new Matrix4(); + + // TextBlock - display list cache. + // Todo: we need a cache eviction strategy. + const int block_cache_capacity = 32; + readonly Dictionary block_cache = new Dictionary(block_cache_capacity); + + bool disposed; + + #endregion + + #region Constructors + + public GL1TextOutputProvider() + { + inactive_lists.Enqueue(new List()); + } + + #endregion + + #region ITextOutputProvider Members + + #region Print + + public void Print(ref TextBlock block, Color color, IGlyphRasterizer rasterizer) + { + GL.PushAttrib(AttribMask.CurrentBit | AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.DepthBufferBit); + + GL.Enable(EnableCap.Texture2D); + GL.Enable(EnableCap.Blend); + SetBlendFunction(); + + GL.Disable(EnableCap.DepthTest); + + GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)All.Modulate); + GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvColor, new Color4(0, 0, 0, 0)); + + GL.Disable(EnableCap.TextureGenQ); + GL.Disable(EnableCap.TextureGenR); + GL.Disable(EnableCap.TextureGenS); + GL.Disable(EnableCap.TextureGenT); + + RectangleF position; + + SetColor(color); + + int block_hash = block.GetHashCode(); + if (block_cache.ContainsKey(block_hash)) + { + GL.CallList(block_cache[block_hash]); + } + else + { + using (TextExtents extents = rasterizer.MeasureText(ref block)) + { + // Build layout + int current = 0; + foreach (Glyph glyph in block) + { + // Do not render whitespace characters or characters outside the clip rectangle. + if (glyph.IsWhiteSpace || extents[current].Width == 0 || extents[current].Height == 0) + { + current++; + continue; + } + else if (!Cache.Contains(glyph)) + Cache.Add(glyph, rasterizer, TextQuality); + + CachedGlyphInfo info = Cache[glyph]; + 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; + + if (!active_lists.ContainsKey(info.Texture)) + { + if (inactive_lists.Count > 0) + { + List list = inactive_lists.Dequeue(); + list.Clear(); + active_lists.Add(info.Texture, list); + } + else + { + active_lists.Add(info.Texture, new List()); + } + } + + { + // Interleaved array: Vertex, TexCoord, Vertex, ... + List current_list = active_lists[info.Texture]; + current_list.Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); + current_list.Add(new Vector2(position.Left, position.Top)); + current_list.Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom)); + current_list.Add(new Vector2(position.Left, position.Bottom)); + current_list.Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); + current_list.Add(new Vector2(position.Right, position.Bottom)); + + current_list.Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); + current_list.Add(new Vector2(position.Right, position.Bottom)); + current_list.Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Top)); + current_list.Add(new Vector2(position.Right, position.Top)); + current_list.Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); + current_list.Add(new Vector2(position.Left, position.Top)); + } + } + } + + // Render + int display_list = 0; + if ((block.Options & TextPrinterOptions.NoCache) == 0) + { + display_list = GL.GenLists(1); + // Mesa Indirect gerates an InvalidOperation error right after + // GL.EndList() when using ListMode.CompileAndExecute. + // Using ListMode.Compile as a workaround. + GL.NewList(display_list, ListMode.Compile); + } + 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(); + } + if ((block.Options & TextPrinterOptions.NoCache) == 0) + { + GL.EndList(); + block_cache.Add(block_hash, display_list); + GL.CallList(display_list); + } + + // Clean layout + foreach (List list in active_lists.Values) + { + //list.Clear(); + inactive_lists.Enqueue(list); + } + + active_lists.Clear(); + } + + GL.PopAttrib(); + } + + #endregion + + #region Clear + + public void Clear() + { + Cache.Clear(); + foreach (int display_list in block_cache.Keys) + GL.DeleteLists(display_list, 1); + block_cache.Clear(); + } + + #endregion + + #region Begin + + public void Begin() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + + GraphicsContext.Assert(); + + // Save the state of everything we are going to modify: + // the current matrix mode, viewport state and the projection, modelview and texture matrices. + // All these will be restored in the TextPrinter.End() method. + int current_matrix; + GL.GetInteger(GetPName.MatrixMode, out current_matrix); + + GL.GetInteger(GetPName.Viewport, out viewport.X); + viewport_stack.Push(viewport); + + GL.GetFloat(GetPName.ProjectionMatrix, out matrix.Row0.X); + projection_stack.Push(matrix); + GL.GetFloat(GetPName.ModelviewMatrix, out matrix.Row0.X); + modelview_stack.Push(matrix); + GL.GetFloat(GetPName.TextureMatrix, out matrix.Row0.X); + texture_stack.Push(matrix); + + // 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.LoadIdentity(); + GL.Ortho(viewport.X, viewport.Width, viewport.Height, viewport.Y, -1.0, 1.0); + + GL.MatrixMode(MatrixMode.Modelview); + GL.LoadIdentity(); + + GL.MatrixMode(MatrixMode.Texture); + 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); + + viewport = viewport_stack.Pop(); + GL.Viewport(viewport.X, viewport.Y, viewport.Width, viewport.Height); + + GL.MatrixMode(MatrixMode.Texture); + matrix = texture_stack.Pop(); + GL.LoadMatrix(ref matrix); + + GL.MatrixMode(MatrixMode.Modelview); + matrix = modelview_stack.Pop(); + GL.LoadMatrix(ref matrix); + + GL.MatrixMode(MatrixMode.Projection); + matrix = projection_stack.Pop(); + GL.LoadMatrix(ref matrix); + + GL.MatrixMode((MatrixMode)current_matrix); + } + + #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.SupportsExtension("Version12") || !GL.SupportsFunction("BlendColor") || quality == TextQuality.Low || quality == TextQuality.Medium) + return new GL11TextOutputProvider(quality); + else + return new GL12TextOutputProvider(quality); + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!disposed) + { + Cache.Dispose(); + disposed = true; + } + } + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/Text/GdiPlusGlyphRasterizer.cs b/Source/Compatibility/Graphics/Text/GdiPlusGlyphRasterizer.cs new file mode 100644 index 00000000..aa9fc60d --- /dev/null +++ b/Source/Compatibility/Graphics/Text/GdiPlusGlyphRasterizer.cs @@ -0,0 +1,501 @@ +#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.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Text; +using OpenTK.Platform; + +namespace OpenTK.Graphics.Text +{ + sealed class GdiPlusGlyphRasterizer : IGlyphRasterizer + { + #region Fields + + // Note: as an optimization, we store the TextBlock hashcode instead of the TextBlock itself. + 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]; + + 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. + // 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' }; + + static readonly SizeF MaximumGraphicsClipSize; + + #endregion + + #region Constructors + + static GdiPlusGlyphRasterizer() + { + using (Bitmap bmp = new Bitmap(1, 1)) + using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp)) + { + MaximumGraphicsClipSize = gfx.ClipBounds.Size; + } + } + + public GdiPlusGlyphRasterizer() + { + measure_string_format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces | StringFormatFlags.NoClip; + measure_string_format_tight.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; + } + + #endregion + + #region IGlyphRasterizer Members + + #region Rasterize + + public Bitmap Rasterize(Glyph glyph) + { + 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, quality); + + RectangleF r2 = new RectangleF(); + + 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); + } + + #endregion + + #region MeasureText + + public TextExtents MeasureText(ref TextBlock block) + { + return MeasureText(ref block, TextQuality.Default); + } + + public TextExtents MeasureText(ref 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. + int hashcode = block.GetHashCode(); + if (block_cache.ContainsKey(hashcode)) + return block_cache[hashcode]; + + // If this block is not cached, we have to measure it and (potentially) place it in the cache. + TextExtents extents = MeasureTextExtents(ref block, quality); + + if ((block.Options & TextPrinterOptions.NoCache) == 0) + block_cache.Add(hashcode, extents); + + return extents; + } + + #endregion + + #region Clear + + public void Clear() + { + block_cache.Clear(); + } + + #endregion + + #endregion + + #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. + void SetTextRenderingOptions(System.Drawing.Graphics gfx, Font font, TextQuality quality) + { + 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(ref TextBlock block, TextQuality quality) + { + // Todo: Parse layout options: + 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 = block.Bounds; + // Work around Mono/GDI+ bug, which causes incorrect + // text wraping when block.Bounds == SizeF.Empty. + if (block.Bounds.Size == SizeF.Empty) + rect.Size = MaximumGraphicsClipSize; + + SetTextRenderingOptions(graphics, block.Font, quality); + + IntPtr native_graphics = GdiPlus.GetNativeGraphics(graphics); + IntPtr native_font = GdiPlus.GetNativeFont(block.Font); + IntPtr native_string_format = GdiPlus.GetNativeStringFormat(format); + + 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 + // 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) + { + float width, height; + + extents.AddRange(MeasureGlyphExtents( + 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; + } + } + + if (extents.Count > 0) + extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, max_width, max_height); + else + extents.BoundingBox = RectangleF.Empty; + + return extents; + } + + #endregion + + #region MeasureGlyphExtents + + // Gets the bounds of each character in a line of text. + // 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; + + int current = 0; + while (current < text.Length) + { + int num_characters = (text.Length - current) > GdiPlus.MaxMeasurableCharacterRanges ? + GdiPlus.MaxMeasurableCharacterRanges : + text.Length - current; + int status = 0; + + // 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); + + 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)); + + // Read back the results of the measurement. + for (int i = 0; i < num_characters; i++) + { + RectangleF rect = new RectangleF(); + + 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)); + + 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; + } + } + + // Mono's GDI+ implementation suffers from an issue where the specified layoutRect is not taken into + // account. We will try to improve the situation by moving text to the correct location on this + // error condition. This will not help word wrapping, but it is better than nothing. + // Todo: Mono 2.8 is supposed to ship with a Pango-based GDI+ text renderer, which should not + // suffer from this bug. Verify that this is the case and remove the hack. + if (Configuration.RunningOnMono && (layoutRect.X != 0 || layoutRect.Y != 0) && measured_glyphs.Count > 0) + { + for (int i = 0; i < measured_glyphs.Count; i++) + { + RectangleF rect = measured_glyphs[i]; + rect.X += layoutRect.X; + rect.Y += layoutRect.Y; + measured_glyphs[i] = rect; + } + } + + return measured_glyphs; + } + + #endregion + + #region FindEdges + + #pragma warning disable 0649 + + struct Pixel { public byte B, G, R, A; } + + #pragma warning restore 0649 + + // 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 = 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); + + return rect; + } + + #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, IntPtr ptr) + { + 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) + { + for (int x = bmp.Width - 1; x >= 0; x--) + for (int y = 0; y < bmp.Height; y++) + unsafe + { + if (((Pixel*)(ptr) + y * bmp.Width + x)->A != 0) + return x + 1; + } + + return 0; + } + + int FindTopEdge(Bitmap bmp, IntPtr ptr) + { + 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) + { + for (int y = bmp.Height - 1; y >= 0; y--) + for (int x = 0; x < bmp.Width; x++) + unsafe + { + if (((Pixel*)(ptr) + y * bmp.Width + x)->A != 0) + return y + 1; + } + + return 0; + } + + #endregion + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/Text/Glyph.cs b/Source/Compatibility/Graphics/Text/Glyph.cs new file mode 100644 index 00000000..e19ff328 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/Glyph.cs @@ -0,0 +1,153 @@ +#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 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 bool IsWhiteSpace + + public bool IsWhiteSpace + { + get { return Char.IsWhiteSpace(Character); } + } + + #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/Compatibility/Graphics/Text/GlyphCache.cs b/Source/Compatibility/Graphics/Text/GlyphCache.cs new file mode 100644 index 00000000..1059dba3 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/GlyphCache.cs @@ -0,0 +1,154 @@ +#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.Drawing; + +namespace OpenTK.Graphics.Text +{ + 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; } + + public abstract void Clear(); + + public abstract void Dispose(); + + #endregion + } + + sealed class GlyphCache : GlyphCache where T : Texture2D + { + #region Fields + + List> sheets = new List>(); + + Dictionary cached_glyphs = new Dictionary(); + + bool disposed; + + const int SheetWidth = 512, SheetHeight = 512; + + #endregion + + #region Constructors + + public GlyphCache() + { + sheets.Add(new GlyphSheet(SheetWidth, SheetHeight)); + } + + #endregion + + #region IGlyphCache Members + + 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, quality)) + { + Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); + foreach (GlyphSheet sheet in sheets) + { + inserted = InsertGlyph(glyph, bmp, rect, sheet); + if (inserted) + break; + } + + if (!inserted) + { + GlyphSheet sheet = new GlyphSheet(SheetWidth, SheetHeight); + sheets.Add(sheet); + InsertGlyph(glyph, bmp, rect, sheet); + } + } + } + + public override bool Contains(Glyph glyph) + { + return cached_glyphs.ContainsKey(glyph); + } + + public override CachedGlyphInfo this[Glyph glyph] + { + get + { + return cached_glyphs[glyph]; + } + } + public override void Clear() + { + for (int i = 0; i < sheets.Count; i++) + sheets[i].Dispose(); + + sheets.Clear(); + } + + #endregion + + #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) + { + 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 + + #region IDisposable Members + + public override void Dispose() + { + if (!disposed) + { + Clear(); + disposed = true; + } + } + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/Text/GlyphEnumerator.cs b/Source/Compatibility/Graphics/Text/GlyphEnumerator.cs new file mode 100644 index 00000000..7ea95a9c --- /dev/null +++ b/Source/Compatibility/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/Compatibility/Graphics/Text/GlyphPacker.cs b/Source/Compatibility/Graphics/Text/GlyphPacker.cs new file mode 100644 index 00000000..5b47c1b8 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/GlyphPacker.cs @@ -0,0 +1,270 @@ +#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 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 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) + + /// + /// 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 cannot fit in the remaining packer space. + public Rectangle Add(Rectangle boundingBox) + { + if (!TryAdd(boundingBox, out boundingBox)) + throw new TexturePackerFullException(); + + return boundingBox; + } + + #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 + + #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/Compatibility/Graphics/Text/GlyphSheet.cs b/Source/Compatibility/Graphics/Text/GlyphSheet.cs new file mode 100644 index 00000000..0c63f7bb --- /dev/null +++ b/Source/Compatibility/Graphics/Text/GlyphSheet.cs @@ -0,0 +1,85 @@ +#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 GlyphSheet : IDisposable where T : Texture2D + { + #region Fields + + readonly T texture; + readonly GlyphPacker packer; + + bool disposed; + + #endregion + + #region Constructors + + public GlyphSheet(int width, int height) + { + texture = (T)typeof(T).GetConstructor(new Type[] { typeof(int), typeof(int) }).Invoke(new object[] { width, height }); + //texture.MagnificationFilter = TextureMagFilter.Nearest; + //texture.MinificationFilter = TextureMinFilter.Nearest; + packer = new GlyphPacker(width, height); + } + + #endregion + + #region Public Members + + public T Texture + { + get { return texture; } + } + + public GlyphPacker Packer + { + get { return packer; } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!disposed) + { + texture.Dispose(); + disposed = true; + } + } + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/Text/IGlyphCache.cs b/Source/Compatibility/Graphics/Text/IGlyphCache.cs new file mode 100644 index 00000000..c6827891 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/IGlyphCache.cs @@ -0,0 +1,39 @@ +#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; + +namespace OpenTK.Graphics.Text +{ + 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/Compatibility/Graphics/Text/IGlyphRasterizer.cs b/Source/Compatibility/Graphics/Text/IGlyphRasterizer.cs new file mode 100644 index 00000000..b3316a2c --- /dev/null +++ b/Source/Compatibility/Graphics/Text/IGlyphRasterizer.cs @@ -0,0 +1,45 @@ +#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.Graphics.Text; + +namespace OpenTK.Graphics.Text +{ + interface IGlyphRasterizer + { + Bitmap Rasterize(Glyph glyph); + Bitmap Rasterize(Glyph glyph, TextQuality quality); + TextExtents MeasureText(ref TextBlock block); + TextExtents MeasureText(ref TextBlock block, TextQuality quality); + void Clear(); + } +} diff --git a/Source/Compatibility/Graphics/Text/ITextOutputProvider.cs b/Source/Compatibility/Graphics/Text/ITextOutputProvider.cs new file mode 100644 index 00000000..ab2fe5c2 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/ITextOutputProvider.cs @@ -0,0 +1,42 @@ +#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 +{ + interface ITextOutputProvider : IDisposable + { + void Print(ref TextBlock block, Color color, IGlyphRasterizer rasterizer); + void Clear(); + void Begin(); + void End(); + } +} diff --git a/Source/Compatibility/Graphics/Text/PoolableTextExtents.cs b/Source/Compatibility/Graphics/Text/PoolableTextExtents.cs new file mode 100644 index 00000000..62444a2d --- /dev/null +++ b/Source/Compatibility/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/Compatibility/Graphics/Text/TextBlock.cs b/Source/Compatibility/Graphics/Text/TextBlock.cs new file mode 100644 index 00000000..a7bea8e8 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/TextBlock.cs @@ -0,0 +1,124 @@ +#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 +{ + // Uniquely identifies a block of text. This structure can be used to identify text blocks for caching. + struct TextBlock : IEquatable, IEnumerable + { + #region Fields + + public readonly string Text; + + public readonly Font Font; + + public readonly RectangleF Bounds; + + public readonly TextPrinterOptions Options; + + public readonly TextAlignment Alignment; + + public readonly TextDirection Direction; + + public readonly int UsageCount; + + #endregion + + #region Constructors + + 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; + } + + #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() ^ Bounds.GetHashCode() ^ Options.GetHashCode(); + } + + public Glyph this[int i] + { + get { return new Glyph(Text[i], Font); } + } + + #endregion + + #region IEquatable Members + + public bool Equals(TextBlock other) + { + return + Text == other.Text && + Font == other.Font && + Bounds == other.Bounds && + Options == other.Options; + } + + #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/Compatibility/Graphics/Text/TextBlockComparer.cs b/Source/Compatibility/Graphics/Text/TextBlockComparer.cs new file mode 100644 index 00000000..08a73499 --- /dev/null +++ b/Source/Compatibility/Graphics/Text/TextBlockComparer.cs @@ -0,0 +1,51 @@ +#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; + +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/Compatibility/Graphics/TextAlignment.cs b/Source/Compatibility/Graphics/TextAlignment.cs new file mode 100644 index 00000000..22d62cd1 --- /dev/null +++ b/Source/Compatibility/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/Compatibility/Graphics/TextDirection.cs b/Source/Compatibility/Graphics/TextDirection.cs new file mode 100644 index 00000000..98a6b946 --- /dev/null +++ b/Source/Compatibility/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/Compatibility/Graphics/TextExtents.cs b/Source/Compatibility/Graphics/TextExtents.cs new file mode 100644 index 00000000..86a7385f --- /dev/null +++ b/Source/Compatibility/Graphics/TextExtents.cs @@ -0,0 +1,136 @@ +#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 +{ + /// + /// Holds the results of a text measurement. + /// + public class TextExtents : IDisposable + { + #region Fields + + protected RectangleF text_extents; + protected List glyph_extents = new List(); + + public static readonly TextExtents Empty = new TextExtents(); + + #endregion + + #region Constructors + + internal TextExtents() + { + } + + #endregion + + #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; } + } + + /// + /// Gets the number of the measured glyphs. + /// + public int Count + { + get { return glyph_extents.Count; } + } + + #endregion + + #region Internal Members + + internal void Add(RectangleF glyphExtent) + { + glyph_extents.Add(glyphExtent); + } + + internal void AddRange(IEnumerable glyphExtents) + { + glyph_extents.AddRange(glyphExtents); + } + + internal void Clear() + { + BoundingBox = RectangleF.Empty; + 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() + { + } + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/TextPrinter.cs b/Source/Compatibility/Graphics/TextPrinter.cs new file mode 100644 index 00000000..67d60320 --- /dev/null +++ b/Source/Compatibility/Graphics/TextPrinter.cs @@ -0,0 +1,338 @@ +#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.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Text.RegularExpressions; +using System.Runtime.InteropServices; +using System.Diagnostics; + +using OpenTK.Graphics; +using OpenTK.Graphics.Text; +using OpenTK.Platform; + +namespace OpenTK.Fonts { } + +namespace OpenTK.Graphics +{ + /// + /// Provides methods to perform layout and print hardware accelerated text. + /// + public sealed class TextPrinter : ITextPrinter + { + #region Fields + + IGlyphRasterizer glyph_rasterizer; + ITextOutputProvider text_output; + TextQuality text_quality; + + bool disposed; + + #endregion + + #region Constructors + + /// + /// 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) { } + + TextPrinter(IGlyphRasterizer rasterizer, ITextOutputProvider output, TextQuality quality) + { + glyph_rasterizer = rasterizer; + text_output = output; + text_quality = quality; + } + + #endregion + + #region ITextPrinter Members + + #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) + throw new ObjectDisposedException(this.GetType().ToString()); + + if (!ValidateParameters(text, font, rect)) + return; + + TextBlock block = new TextBlock(text, font, rect, options, alignment, direction); + TextOutput.Print(ref block, color, Rasterizer); + } + + #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. + /// 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) + throw new ObjectDisposedException(this.GetType().ToString()); + + if (!ValidateParameters(text, font, rect)) + return TextExtents.Empty; + + TextBlock block = new TextBlock(text, font, rect, options, alignment, direction); + return Rasterizer.MeasureText(ref block); + } + + #endregion + + #region Clear + + public void Clear() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().ToString()); + + TextOutput.Clear(); + Rasterizer.Clear(); + } + + #endregion + + #region Begin + + /// + /// Sets up a resolution-dependent orthographic projection. + /// + public void Begin() + { + TextOutput.Begin(); + } + + #endregion + + #region Begin + + /// + /// Restores the projection and modelview matrices to their previous state. + /// + public void End() + { + TextOutput.End(); + } + + #endregion + + #region Obsolete + + [Obsolete("Use TextPrinter.Print instead")] + public void Draw(TextHandle handle) + { + Print(handle.Text, handle.GdiPFont, Color.White); + } + + [Obsolete("Use TextPrinter.Print instead")] + public void Draw(string text, TextureFont font) + { + Print(text, font.font, Color.White); + } + + [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 + + 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, RectangleF rect) + { + if (String.IsNullOrEmpty(text)) + return false; + if (font == null) + throw new ArgumentNullException("font"); + if (rect.Width < 0 || rect.Height < 0) + throw new ArgumentOutOfRangeException("rect"); + + return true; + } + + #endregion + + #region IDisposable Members + + /// + /// Frees the resources consumed by this TextPrinter object. + /// + public void Dispose() + { + if (!disposed) + { + TextOutput.Dispose(); + disposed = true; + } + } + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/TextPrinterOptions.cs b/Source/Compatibility/Graphics/TextPrinterOptions.cs new file mode 100644 index 00000000..34275da6 --- /dev/null +++ b/Source/Compatibility/Graphics/TextPrinterOptions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Graphics +{ + /// + /// Defines available options for the TextPrinter. + /// + [Flags] + public enum TextPrinterOptions + { + /// 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/Compatibility/Graphics/TextQuality.cs b/Source/Compatibility/Graphics/TextQuality.cs new file mode 100644 index 00000000..311a488d --- /dev/null +++ b/Source/Compatibility/Graphics/TextQuality.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +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 + } +} diff --git a/Source/Compatibility/Graphics/Texture2D.cs b/Source/Compatibility/Graphics/Texture2D.cs new file mode 100644 index 00000000..1d85c742 --- /dev/null +++ b/Source/Compatibility/Graphics/Texture2D.cs @@ -0,0 +1,320 @@ +#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; +using System.Diagnostics; + +namespace OpenTK.Graphics +{ + abstract class Texture2D : IGraphicsResource, IEquatable + { + #region Fields + + IGraphicsContext 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.Bgra, + 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, OpenTK.Graphics.PixelFormat.Bgra, PixelType.UnsignedByte, region.Data); + + return region; + } + + #endregion + + #region Equals + + public override bool Equals(object obj) + { + if (obj is Texture2D) + return this.Equals((Texture2D)obj); + + return false; + } + + #endregion + + #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 + + #region Protected Members + + #region InternalFormat + + protected abstract PixelInternalFormat InternalFormat { get; } + + #endregion + + #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())); + + SetDefaultTextureParameters(id); + + 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 + + IGraphicsContext IGraphicsResource.Context { get { return context; } } + + #endregion + + #region IGraphicsResource.Id + + int IGraphicsResource.Id + { + get + { + if (id == 0) + { + GraphicsContext.Assert(); + context = GraphicsContext.CurrentContext; + + id = CreateTexture(Width, Height); + } + + return id; + } + } + + #endregion + + #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() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool manual) + { + if (!disposed) + { + if (manual) + { + GL.DeleteTexture(id); + } + else + { + Debug.Print("[Warning] {0} leaked.", this); + } + disposed = true; + } + } + + ~Texture2D() + { + Dispose(false); + } + + #endregion + } +} diff --git a/Source/Compatibility/Graphics/TextureRegion2D.cs b/Source/Compatibility/Graphics/TextureRegion2D.cs new file mode 100644 index 00000000..248aba32 --- /dev/null +++ b/Source/Compatibility/Graphics/TextureRegion2D.cs @@ -0,0 +1,79 @@ +#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 +{ + 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 + } +}