mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-24 16:35:36 +00:00
First public commit of the new text renderer (WIP implementation).
This commit is contained in:
parent
f853a7b021
commit
a57eb8f647
|
@ -164,30 +164,30 @@ namespace Examples.Tutorial
|
||||||
PixelType.UnsignedByte, data.Scan0);
|
PixelType.UnsignedByte, data.Scan0);
|
||||||
bitmap.UnlockBits(data);
|
bitmap.UnlockBits(data);
|
||||||
}
|
}
|
||||||
#endregion Textures
|
#endregion Textures
|
||||||
|
|
||||||
Keyboard.KeyUp += KeyUp;
|
Keyboard.KeyUp += KeyUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
void KeyUp(OpenTK.Input.KeyboardDevice sender, OpenTK.Input.Key e)
|
void KeyUp(OpenTK.Input.KeyboardDevice sender, OpenTK.Input.Key e)
|
||||||
{
|
{
|
||||||
if (e == OpenTK.Input.Key.F12)
|
if (e == OpenTK.Input.Key.F12)
|
||||||
{
|
{
|
||||||
Bitmap bmp = new Bitmap(this.Width, this.Height);
|
Bitmap bmp = new Bitmap(this.Width, this.Height);
|
||||||
System.Drawing.Imaging.BitmapData data =
|
System.Drawing.Imaging.BitmapData data =
|
||||||
bmp.LockBits(new Rectangle(0, 0, this.Width, this.Height),
|
bmp.LockBits(new Rectangle(0, 0, this.Width, this.Height),
|
||||||
System.Drawing.Imaging.ImageLockMode.WriteOnly,
|
System.Drawing.Imaging.ImageLockMode.WriteOnly,
|
||||||
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
||||||
GL.ReadPixels(0, 0, this.Width, this.Height,
|
GL.ReadPixels(0, 0, this.Width, this.Height,
|
||||||
OpenTK.Graphics.PixelFormat.Bgr,
|
OpenTK.Graphics.PixelFormat.Bgr,
|
||||||
OpenTK.Graphics.PixelType.UnsignedByte,
|
OpenTK.Graphics.PixelType.UnsignedByte,
|
||||||
data.Scan0);
|
data.Scan0);
|
||||||
bmp.UnlockBits(data);
|
bmp.UnlockBits(data);
|
||||||
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
||||||
bmp.Save("Screenshot" + (i++).ToString() + ".png", ImageFormat.Png);
|
bmp.Save("Screenshot" + (i++).ToString() + ".png", ImageFormat.Png);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ namespace Examples.Tutorial
|
||||||
if (Keyboard[OpenTK.Input.Key.Escape])
|
if (Keyboard[OpenTK.Input.Key.Escape])
|
||||||
{
|
{
|
||||||
this.Exit();
|
this.Exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Examples.Tests
|
||||||
public class MathSpeed
|
public class MathSpeed
|
||||||
{
|
{
|
||||||
public static void Main()
|
public static void Main()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Stopwatch watch = new Stopwatch();
|
Stopwatch watch = new Stopwatch();
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,11 @@ namespace Examples.Tutorial
|
||||||
[Example("Text", ExampleCategory.Tutorial, 4)]
|
[Example("Text", ExampleCategory.Tutorial, 4)]
|
||||||
public class Text : GameWindow
|
public class Text : GameWindow
|
||||||
{
|
{
|
||||||
TextureFont serif = new TextureFont(new Font(FontFamily.GenericSerif, 24.0f));
|
Font serif2 = new Font(FontFamily.GenericSerif, 14.0f);
|
||||||
|
TextureFont serif = new TextureFont(new Font(FontFamily.GenericSerif, 12.0f));
|
||||||
TextureFont sans = new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f));
|
TextureFont sans = new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f));
|
||||||
TextHandle poem_handle;
|
TextHandle poem_handle;
|
||||||
ITextPrinter text = new TextPrinter();
|
TextPrinter text = new TextPrinter();
|
||||||
|
|
||||||
string poem = new StreamReader("Data/Poem.txt").ReadToEnd();
|
string poem = new StreamReader("Data/Poem.txt").ReadToEnd();
|
||||||
int lines; // How many lines the poem contains.
|
int lines; // How many lines the poem contains.
|
||||||
|
@ -125,11 +126,14 @@ namespace Examples.Tutorial
|
||||||
// used in 2d graphics, and is necessary for achieving pixel-perfect glyph rendering.
|
// used in 2d graphics, and is necessary for achieving pixel-perfect glyph rendering.
|
||||||
// TextPrinter.End() restores your previous projection/modelview matrices.
|
// TextPrinter.End() restores your previous projection/modelview matrices.
|
||||||
text.Begin();
|
text.Begin();
|
||||||
GL.Color3(Color.LightBlue);
|
//GL.Color3(Color.LightBlue);
|
||||||
text.Draw((1.0 / e.Time).ToString("F2"), sans);
|
//text.Draw((1.0 / e.Time).ToString("F2"), sans);
|
||||||
GL.Translate(0.0f, current_position, 0.0f);
|
GL.Translate(0.0f, current_position, 0.0f);
|
||||||
GL.Color3(Color.White);
|
GL.Color3(Color.White);
|
||||||
text.Draw(poem_handle);
|
//text.Draw(poem_handle);
|
||||||
|
//text.Draw(poem, serif);
|
||||||
|
//GL.BindTexture(TextureTarget.Texture2D, 1);
|
||||||
|
text.Print(poem, serif2);
|
||||||
text.End();
|
text.End();
|
||||||
|
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
|
|
|
@ -111,12 +111,29 @@ namespace OpenTK.Graphics
|
||||||
/// <returns>A System.Int32 containing a hashcode that uniquely identifies this Glyph.</returns>
|
/// <returns>A System.Int32 containing a hashcode that uniquely identifies this Glyph.</returns>
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
//return character.GetHashCode() ^ font.Style.GetHashCode() ^ font.Size.GetHashCode() ^ font.Unit.GetHashCode();
|
|
||||||
return character.GetHashCode() ^ font.GetHashCode() ^ size.GetHashCode();
|
return character.GetHashCode() ^ font.GetHashCode() ^ size.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region public SizeF Size
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size of this Glyph.
|
||||||
|
/// </summary>
|
||||||
|
public SizeF Size { get { return size; } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public RectangleF Rectangle
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the bounding box of this Glyph.
|
||||||
|
/// </summary>
|
||||||
|
public RectangleF Rectangle { get { return new RectangleF(PointF.Empty, Size); } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region --- IPackable<T> Members ---
|
#region --- IPackable<T> Members ---
|
||||||
|
@ -154,7 +171,7 @@ namespace OpenTK.Graphics
|
||||||
/// <returns>True if both Glyphs represent the same character of the same Font, false otherwise.</returns>
|
/// <returns>True if both Glyphs represent the same character of the same Font, false otherwise.</returns>
|
||||||
public bool Equals(Glyph other)
|
public bool Equals(Glyph other)
|
||||||
{
|
{
|
||||||
return Character == other.Character && Font == other.Font;
|
return Character == other.Character && Font == other.Font && Size == other.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -12,11 +12,12 @@ using System.Text;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
using OpenTK.Math;
|
using OpenTK.Math;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Graphics.OpenGL.Enums;
|
using OpenTK.Graphics.Text;
|
||||||
using System.Diagnostics;
|
using OpenTK.Platform;
|
||||||
|
|
||||||
namespace OpenTK.Fonts { }
|
namespace OpenTK.Fonts { }
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ namespace OpenTK.Graphics
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides methods to perform layout and print hardware accelerated text.
|
/// Provides methods to perform layout and print hardware accelerated text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TextPrinter : ITextPrinter
|
public sealed class TextPrinter : ITextPrinter
|
||||||
{
|
{
|
||||||
//static Regex break_point = new Regex("[ .,/*-+?\\!=]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
//static Regex break_point = new Regex("[ .,/*-+?\\!=]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
//static char[] split_chars = new char[]
|
//static char[] split_chars = new char[]
|
||||||
|
@ -42,11 +43,6 @@ namespace OpenTK.Graphics
|
||||||
|
|
||||||
#region --- Constructors ---
|
#region --- Constructors ---
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new TextPrinter object.
|
|
||||||
/// </summary>
|
|
||||||
public TextPrinter() { }
|
|
||||||
|
|
||||||
public TextPrinter(ITextPrinterImplementation implementation)
|
public TextPrinter(ITextPrinterImplementation implementation)
|
||||||
{
|
{
|
||||||
if (implementation == null)
|
if (implementation == null)
|
||||||
|
@ -359,5 +355,154 @@ namespace OpenTK.Graphics
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region New Implementation
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
Dictionary<Font, TextureFont> font_cache = new Dictionary<Font, TextureFont>();
|
||||||
|
|
||||||
|
GlyphCache glyph_cache;
|
||||||
|
IGlyphRasterizer glyph_rasterizer;
|
||||||
|
ITextOutputProvider text_output;
|
||||||
|
|
||||||
|
//TextExtents text_extents = new TextExtents();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new TextPrinter object.
|
||||||
|
/// </summary>
|
||||||
|
public TextPrinter()
|
||||||
|
: this(null, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextPrinter(IGlyphRasterizer rasterizer, ITextOutputProvider output/*, IGlyphCacheProvider, ITextOutputProvider */)
|
||||||
|
{
|
||||||
|
if (rasterizer == null)
|
||||||
|
rasterizer = new GdiPlusGlyphRasterizer();
|
||||||
|
|
||||||
|
if (output == null)
|
||||||
|
output = new GL1TextOutputProvider();
|
||||||
|
|
||||||
|
glyph_rasterizer = rasterizer;
|
||||||
|
glyph_cache = new GlyphCache(rasterizer);
|
||||||
|
text_output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Members
|
||||||
|
|
||||||
|
#region Print
|
||||||
|
|
||||||
|
public void Print(string text, Font font)
|
||||||
|
{
|
||||||
|
Print(text, font, 0, RectangleF.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Print(string text, Font font, TextPrinterOptions options)
|
||||||
|
{
|
||||||
|
Print(text, font, options, RectangleF.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Print(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrEmpty(text))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (font == null)
|
||||||
|
throw new ArgumentNullException("font");
|
||||||
|
|
||||||
|
text_output.Print(new TextBlock(text, font, options, layoutRectangle), glyph_rasterizer, glyph_cache);
|
||||||
|
|
||||||
|
//glyph_rasterizer.MeasureText(text, font, options, layoutRectangle, ref text_extents);
|
||||||
|
|
||||||
|
//List<Vector2> vertices = new List<Vector2>();
|
||||||
|
//List<int> indices = new List<int>();
|
||||||
|
//PerformLayout(new TextBlock(text, font, layoutRectangle, options), text_extents, vertices, indices);
|
||||||
|
|
||||||
|
//GL.Begin(BeginMode.Triangles);
|
||||||
|
//foreach (int i in indices)
|
||||||
|
//{
|
||||||
|
// GL.TexCoord2(vertices[i + 1]);
|
||||||
|
// GL.Vertex2(vertices[i]);
|
||||||
|
//}
|
||||||
|
//GL.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
#region PerformLayout
|
||||||
|
|
||||||
|
void PerformLayout(TextBlock block, TextExtents extents, List<Vector2> vertices, List<int> indices)
|
||||||
|
{
|
||||||
|
vertices.Clear();
|
||||||
|
vertices.Capacity = 4 * block.Text.Length;
|
||||||
|
indices.Clear();
|
||||||
|
indices.Capacity = 6 * block.Text.Length;
|
||||||
|
|
||||||
|
float x_pos = 0, y_pos = 0;
|
||||||
|
RectangleF rect = new RectangleF();
|
||||||
|
float char_width, char_height;
|
||||||
|
|
||||||
|
// Every character comprises of 4 vertices, forming two triangles. We generate an index array which
|
||||||
|
// indexes vertices in a triangle-list fashion.
|
||||||
|
|
||||||
|
int current = 0;
|
||||||
|
foreach (char c in block.Text)
|
||||||
|
{
|
||||||
|
if (c == '\n' || c == '\r')
|
||||||
|
continue;
|
||||||
|
else if (Char.IsWhiteSpace(c))
|
||||||
|
{
|
||||||
|
current++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (!glyph_cache.Contains(c, block.Font))
|
||||||
|
glyph_cache.Add(c, block.Font);
|
||||||
|
|
||||||
|
//font.GlyphData(c, out char_width, out char_height, out rect, out texture);
|
||||||
|
CachedGlyphInfo cache_info = glyph_cache[c, block.Font];
|
||||||
|
RectangleF glyph_position = extents[current];
|
||||||
|
|
||||||
|
x_pos = glyph_position.X;
|
||||||
|
y_pos = glyph_position.Y;
|
||||||
|
char_width = glyph_position.Width;
|
||||||
|
char_height = glyph_position.Height;
|
||||||
|
|
||||||
|
// Interleaved array: Vertex, TexCoord, Vertex, ...
|
||||||
|
vertices.Add(new Vector2(x_pos, y_pos)); // Vertex
|
||||||
|
vertices.Add(new Vector2(rect.Left, rect.Top)); // Texcoord
|
||||||
|
vertices.Add(new Vector2(x_pos, y_pos + char_height));
|
||||||
|
vertices.Add(new Vector2(rect.Left, rect.Bottom));
|
||||||
|
|
||||||
|
vertices.Add(new Vector2(x_pos + char_width, y_pos + char_height));
|
||||||
|
vertices.Add(new Vector2(rect.Right, rect.Bottom));
|
||||||
|
vertices.Add(new Vector2(x_pos + char_width, y_pos));
|
||||||
|
vertices.Add(new Vector2(rect.Right, rect.Top));
|
||||||
|
|
||||||
|
indices.Add(vertices.Count - 8);
|
||||||
|
indices.Add(vertices.Count - 6);
|
||||||
|
indices.Add(vertices.Count - 4);
|
||||||
|
|
||||||
|
indices.Add(vertices.Count - 4);
|
||||||
|
indices.Add(vertices.Count - 2);
|
||||||
|
indices.Add(vertices.Count - 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
Source/Utilities/Fonts/TextPrinterOptions.cs
Normal file
14
Source/Utilities/Fonts/TextPrinterOptions.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum TextPrinterOptions
|
||||||
|
{
|
||||||
|
NoCache = 1,
|
||||||
|
RightToLeft = 2,
|
||||||
|
Vertical = 4,
|
||||||
|
}
|
||||||
|
}
|
35
Source/Utilities/Graphics/CachedGlyphInfo.cs
Normal file
35
Source/Utilities/Graphics/CachedGlyphInfo.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics
|
||||||
|
{
|
||||||
|
struct CachedGlyphInfo
|
||||||
|
{
|
||||||
|
public readonly AlphaTexture2D Texture;
|
||||||
|
public readonly RectangleF RectangleNormalized;
|
||||||
|
public Rectangle Rectangle
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Rectangle(
|
||||||
|
(int)(RectangleNormalized.X * Texture.Width),
|
||||||
|
(int)(RectangleNormalized.Y * Texture.Height),
|
||||||
|
(int)(RectangleNormalized.Width * Texture.Width),
|
||||||
|
(int)(RectangleNormalized.Height * Texture.Height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rect denotes the absolute position of the glyph in the texture [0, Texture.Width], [0, Texture.Height].
|
||||||
|
public CachedGlyphInfo(AlphaTexture2D texture, Rectangle rect)
|
||||||
|
{
|
||||||
|
Texture = texture;
|
||||||
|
RectangleNormalized = new RectangleF(
|
||||||
|
rect.X / (float)texture.Width,
|
||||||
|
rect.Y / (float)texture.Height,
|
||||||
|
rect.Width / (float)texture.Width,
|
||||||
|
rect.Height / (float)texture.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Source/Utilities/Graphics/GraphicsResourceException.cs
Normal file
17
Source/Utilities/Graphics/GraphicsResourceException.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents exceptions related to IGraphicsResources.
|
||||||
|
/// </summary>
|
||||||
|
public class GraphicsResourceException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>Constructs a new GraphicsResourceException.</summary>
|
||||||
|
public GraphicsResourceException() : base() { }
|
||||||
|
/// <summary>Constructs a new string with the specified error message.</summary>
|
||||||
|
public GraphicsResourceException(string message) : base(message) { }
|
||||||
|
}
|
||||||
|
}
|
22
Source/Utilities/Graphics/IGraphicsResource.cs
Normal file
22
Source/Utilities/Graphics/IGraphicsResource.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a common interface to all OpenGL resources.
|
||||||
|
/// </summary>
|
||||||
|
interface IGraphicsResource : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the GraphicsContext that owns this resource.
|
||||||
|
/// </summary>
|
||||||
|
GraphicsContext Context { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Id of this IGraphicsResource.
|
||||||
|
/// </summary>
|
||||||
|
int Id { get; }
|
||||||
|
}
|
||||||
|
}
|
84
Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs
Normal file
84
Source/Utilities/Graphics/Text/GL1TextOutputProvider.cs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
class GL1TextOutputProvider : ITextOutputProvider
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public GL1TextOutputProvider() { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ITextOutputProvider Members
|
||||||
|
|
||||||
|
public void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache)
|
||||||
|
{
|
||||||
|
TextExtents extents = rasterizer.MeasureText(block);
|
||||||
|
|
||||||
|
foreach (char c in block.Text)
|
||||||
|
if (c != '\n' && c != '\r' && !Char.IsWhiteSpace(c) && !cache.Contains(c, block.Font))
|
||||||
|
cache.Add(c, block.Font);
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, 1);
|
||||||
|
|
||||||
|
//GL.Begin(BeginMode.Quads);
|
||||||
|
|
||||||
|
//GL.TexCoord2(0, 0);
|
||||||
|
//GL.Vertex2(0, 0);
|
||||||
|
//GL.TexCoord2(1, 0);
|
||||||
|
//GL.Vertex2(256, 0);
|
||||||
|
//GL.TexCoord2(1, 1);
|
||||||
|
//GL.Vertex2(256, 256);
|
||||||
|
//GL.TexCoord2(0, 1);
|
||||||
|
//GL.Vertex2(0, 256);
|
||||||
|
|
||||||
|
//GL.End();
|
||||||
|
|
||||||
|
//GL.Translate(0, 256, 0);
|
||||||
|
|
||||||
|
//GL.Disable(EnableCap.Texture2D);
|
||||||
|
//GL.BindTexture(TextureTarget.Texture2D, 1);
|
||||||
|
GL.Begin(BeginMode.Triangles);
|
||||||
|
|
||||||
|
int current = 0;
|
||||||
|
foreach (char c in block.Text)
|
||||||
|
{
|
||||||
|
if (c == '\n' || c == '\r')
|
||||||
|
continue;
|
||||||
|
else if (Char.IsWhiteSpace(c))
|
||||||
|
{
|
||||||
|
current++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedGlyphInfo info = cache[c, block.Font];
|
||||||
|
RectangleF position = extents[current++];
|
||||||
|
|
||||||
|
position.Size = info.Rectangle.Size;
|
||||||
|
|
||||||
|
// Interleaved array: Vertex, TexCoord, Vertex, ...
|
||||||
|
GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Top);
|
||||||
|
GL.Vertex2(position.Left, position.Top);
|
||||||
|
GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom);
|
||||||
|
GL.Vertex2(position.Left, position.Bottom);
|
||||||
|
GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom);
|
||||||
|
GL.Vertex2(position.Right, position.Bottom);
|
||||||
|
|
||||||
|
GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom);
|
||||||
|
GL.Vertex2(position.Right, position.Bottom);
|
||||||
|
GL.TexCoord2(info.RectangleNormalized.Right, info.RectangleNormalized.Top);
|
||||||
|
GL.Vertex2(position.Right, position.Top);
|
||||||
|
GL.TexCoord2(info.RectangleNormalized.Left, info.RectangleNormalized.Top);
|
||||||
|
GL.Vertex2(position.Left, position.Top);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
117
Source/Utilities/Graphics/Text/Glyph.cs
Normal file
117
Source/Utilities/Graphics/Text/Glyph.cs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
struct Glyph : IEquatable<Glyph>
|
||||||
|
{
|
||||||
|
char character;
|
||||||
|
Font font;
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new Glyph that represents the given character and Font.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c">The character to represent.</param>
|
||||||
|
/// <param name="f">The Font of the character.</param>
|
||||||
|
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
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the character represented by this Glyph.
|
||||||
|
/// </summary>
|
||||||
|
public char Character
|
||||||
|
{
|
||||||
|
get { return character; }
|
||||||
|
private set { character = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public Font Font
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Font of this Glyph.
|
||||||
|
/// </summary>
|
||||||
|
public Font Font
|
||||||
|
{
|
||||||
|
get { return font; }
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
throw new ArgumentNullException("Font", "Glyph font cannot be null");
|
||||||
|
|
||||||
|
font = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public override bool Equals(object obj)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the given object is equal (memberwise) to the current Glyph.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj to check.</param>
|
||||||
|
/// <returns>True, if the object is identical to the current Glyph.</returns>
|
||||||
|
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()
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Describes this Glyph object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a System.String describing this Glyph.</returns>
|
||||||
|
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()
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the hashcode for this Glyph.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A System.Int32 containing a hashcode that uniquely identifies this Glyph.</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return character.GetHashCode() ^ font.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEquatable<Glyph> Members
|
||||||
|
|
||||||
|
public bool Equals(Glyph other)
|
||||||
|
{
|
||||||
|
return Character == other.Character && Font == other.Font;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
100
Source/Utilities/Graphics/Text/GlyphCache.cs
Normal file
100
Source/Utilities/Graphics/Text/GlyphCache.cs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
class GlyphCache
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
IGlyphRasterizer rasterizer;
|
||||||
|
List<GlyphSheet> sheets = new List<GlyphSheet>();
|
||||||
|
Bitmap bmp = new Bitmap(256, 256);
|
||||||
|
|
||||||
|
Dictionary<Glyph, CachedGlyphInfo> cached_glyphs = new Dictionary<Glyph, CachedGlyphInfo>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public GlyphCache(IGlyphRasterizer rasterizer)
|
||||||
|
{
|
||||||
|
if (rasterizer == null)
|
||||||
|
throw new ArgumentNullException("rasterizer");
|
||||||
|
|
||||||
|
this.rasterizer = rasterizer;
|
||||||
|
sheets.Add(new GlyphSheet());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Members
|
||||||
|
|
||||||
|
public void Add(char c, Font font)
|
||||||
|
{
|
||||||
|
Glyph glyph = new Glyph(c, font);
|
||||||
|
bool inserted = false;
|
||||||
|
|
||||||
|
using (Bitmap bmp = rasterizer.Rasterize(glyph))
|
||||||
|
{
|
||||||
|
foreach (GlyphSheet sheet in sheets)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InsertGlyph(glyph, bmp, sheet);
|
||||||
|
inserted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (TexturePackerFullException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inserted)
|
||||||
|
{
|
||||||
|
GlyphSheet sheet = new GlyphSheet();
|
||||||
|
sheets.Add(sheet);
|
||||||
|
InsertGlyph(glyph, bmp, sheet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertGlyph(Glyph glyph, Bitmap bmp, GlyphSheet sheet)
|
||||||
|
{
|
||||||
|
Rectangle source = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
||||||
|
Rectangle target = sheet.Packer.Add(source);
|
||||||
|
|
||||||
|
sheet.Texture.WriteRegion(source, target, 0, bmp);
|
||||||
|
|
||||||
|
cached_glyphs.Add(glyph, new CachedGlyphInfo(sheet.Texture, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(char c, Font font)
|
||||||
|
{
|
||||||
|
return cached_glyphs.ContainsKey(new Glyph(c, font));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedGlyphInfo this[char c, Font font]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return cached_glyphs[new Glyph(c, font)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedGlyphInfo this[Glyph glyph]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return cached_glyphs[glyph];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
208
Source/Utilities/Graphics/Text/GlyphPacker.cs
Normal file
208
Source/Utilities/Graphics/Text/GlyphPacker.cs
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
class GlyphPacker
|
||||||
|
{
|
||||||
|
Node root;
|
||||||
|
|
||||||
|
#region --- Constructors ---
|
||||||
|
|
||||||
|
public GlyphPacker(int width, int height)
|
||||||
|
{
|
||||||
|
if (width <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException("width", width, "Must be greater than zero.");
|
||||||
|
if (height <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException("height", height, "Must be greater than zero.");
|
||||||
|
|
||||||
|
root = new Node();
|
||||||
|
root.Rectangle = new Rectangle(0, 0, width, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region --- Public Methods ---
|
||||||
|
|
||||||
|
#region public Rectangle Add(Rectangle boundingBox)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds boundingBox to the GlyphPacker.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="boundingBox">The bounding box of the item to pack.</param>
|
||||||
|
/// <returns>A System.Drawing.Rectangle containing the coordinates of the packed item.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Occurs if the item is larger than the available TexturePacker area</exception>
|
||||||
|
/// <exception cref="ArgumentException">Occurs if the item already exists in the TexturePacker.</exception>
|
||||||
|
public Rectangle Add(Rectangle boundingBox)
|
||||||
|
{
|
||||||
|
if (!root.Rectangle.Contains(boundingBox))
|
||||||
|
throw new InvalidOperationException("The item is too large for this TexturePacker");
|
||||||
|
|
||||||
|
Node node;
|
||||||
|
node = root.Insert(boundingBox);
|
||||||
|
|
||||||
|
// Tree is full and insertion failed:
|
||||||
|
if (node == null)
|
||||||
|
throw new TexturePackerFullException();
|
||||||
|
|
||||||
|
return node.Rectangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public Rectangle Add(RectangleF boundingBox)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rounds boundingBox to the largest integer and adds the resulting Rectangle to the GlyphPacker.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="boundingBox">The bounding box of the item to pack.</param>
|
||||||
|
/// <returns>A System.Drawing.Rectangle containing the coordinates of the packed item.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Occurs if the item is larger than the available TexturePacker area</exception>
|
||||||
|
/// <exception cref="ArgumentException">Occurs if the item already exists in the TexturePacker.</exception>
|
||||||
|
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()
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Discards all packed items.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
root.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public void ChangeSize(int new_width, int new_height)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the dimensions of the TexturePacker surface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="new_width">The new width of the TexturePacker surface.</param>
|
||||||
|
/// <param name="new_height">The new height of the TexturePacker surface.</param>
|
||||||
|
/// <remarks>Changing the size of the TexturePacker surface will implicitly call TexturePacker.Clear().</remarks>
|
||||||
|
/// <seealso cref="Clear"/>
|
||||||
|
public void ChangeSize(int new_width, int new_height)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Node
|
||||||
|
|
||||||
|
class Node
|
||||||
|
{
|
||||||
|
public Node()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Node left, right;
|
||||||
|
Rectangle rect;
|
||||||
|
bool occupied;
|
||||||
|
|
||||||
|
public Rectangle Rectangle { get { return rect; } set { rect = value; } }
|
||||||
|
public Node Left { get { return left; } set { left = value; } }
|
||||||
|
public Node Right { get { return right; } set { right = value; } }
|
||||||
|
|
||||||
|
#region --- Constructor ---
|
||||||
|
|
||||||
|
public bool Leaf
|
||||||
|
{
|
||||||
|
get { return left == null && right == null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Node Insert(Rectangle bbox)
|
||||||
|
|
||||||
|
public Node Insert( Rectangle bbox)
|
||||||
|
{
|
||||||
|
if (!this.Leaf)
|
||||||
|
{
|
||||||
|
// Recurse towards left child, and if that fails, towards the right.
|
||||||
|
Node new_node = left.Insert(bbox);
|
||||||
|
return new_node ?? right.Insert(bbox);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We have recursed to a leaf.
|
||||||
|
|
||||||
|
// If it is not empty go back.
|
||||||
|
if (occupied)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// If this leaf is too small go back.
|
||||||
|
if (rect.Width < bbox.Width || rect.Height < bbox.Height)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// If this leaf is the right size, insert here.
|
||||||
|
if (rect.Width == bbox.Width && rect.Height == bbox.Height)
|
||||||
|
{
|
||||||
|
occupied = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This leaf is too large, split it up. We'll decide which way to split
|
||||||
|
// by checking the width and height difference between this rectangle and
|
||||||
|
// out item's bounding box. If the width difference is larger, we'll split
|
||||||
|
// horizontaly, else verticaly.
|
||||||
|
left = new Node();
|
||||||
|
right = new Node();
|
||||||
|
|
||||||
|
int dw = this.rect.Width - bbox.Width + 1;
|
||||||
|
int dh = this.rect.Height - bbox.Height + 1;
|
||||||
|
|
||||||
|
if (dw > dh)
|
||||||
|
{
|
||||||
|
left.rect = new Rectangle(rect.Left, rect.Top, bbox.Width, rect.Height);
|
||||||
|
right.rect = new Rectangle(rect.Left + bbox.Width, rect.Top, rect.Width - bbox.Width, rect.Height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
left.rect = new Rectangle(rect.Left, rect.Top, rect.Width, bbox.Height);
|
||||||
|
right.rect = new Rectangle(rect.Left, rect.Top + bbox.Height, rect.Width, rect.Height - bbox.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return left.Insert(bbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public void Clear()
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
if (left != null)
|
||||||
|
left.Clear();
|
||||||
|
if (right != null)
|
||||||
|
right.Clear();
|
||||||
|
|
||||||
|
left = right = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
class TexturePackerFullException : Exception
|
||||||
|
{
|
||||||
|
public TexturePackerFullException() : base("There is not enough space to add this item. Consider calling the Clear() method.") { }
|
||||||
|
}
|
||||||
|
}
|
43
Source/Utilities/Graphics/Text/GlyphSheet.cs
Normal file
43
Source/Utilities/Graphics/Text/GlyphSheet.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
class GlyphSheet
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
AlphaTexture2D texture;
|
||||||
|
GlyphPacker packer;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public GlyphSheet()
|
||||||
|
{
|
||||||
|
Texture = new AlphaTexture2D(256, 256);
|
||||||
|
Packer = new GlyphPacker(256, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Members
|
||||||
|
|
||||||
|
public AlphaTexture2D Texture
|
||||||
|
{
|
||||||
|
get { return texture; }
|
||||||
|
private set { texture = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlyphPacker Packer
|
||||||
|
{
|
||||||
|
get { return packer; }
|
||||||
|
private set { packer = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
17
Source/Utilities/Graphics/Text/IGlyphRasterizer.cs
Normal file
17
Source/Utilities/Graphics/Text/IGlyphRasterizer.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
using OpenTK.Graphics.Text;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
interface IGlyphRasterizer
|
||||||
|
{
|
||||||
|
Bitmap Rasterize(Glyph glyph);
|
||||||
|
//void Rasterize(Glyph glyph, ref Bitmap bmp);
|
||||||
|
TextExtents MeasureText(TextBlock block);
|
||||||
|
RectangleF MeasureGlyph(Glyph glyph);
|
||||||
|
}
|
||||||
|
}
|
11
Source/Utilities/Graphics/Text/ITextOutputProvider.cs
Normal file
11
Source/Utilities/Graphics/Text/ITextOutputProvider.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
interface ITextOutputProvider
|
||||||
|
{
|
||||||
|
void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache);
|
||||||
|
}
|
||||||
|
}
|
68
Source/Utilities/Graphics/Text/TextBlock.cs
Normal file
68
Source/Utilities/Graphics/Text/TextBlock.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
// Uniquely identifies a block of text. This structure can be used to identify text blocks for caching.
|
||||||
|
struct TextBlock : IEquatable<TextBlock>
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public readonly string Text;
|
||||||
|
|
||||||
|
public readonly Font Font;
|
||||||
|
|
||||||
|
public readonly RectangleF LayoutRectangle;
|
||||||
|
|
||||||
|
public readonly TextPrinterOptions Options;
|
||||||
|
|
||||||
|
public int UsageCount; // Used to identify old and unused blocks of text.
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public TextBlock(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle)
|
||||||
|
{
|
||||||
|
Text = text;
|
||||||
|
Font = font;
|
||||||
|
LayoutRectangle = layoutRectangle;
|
||||||
|
Options = options;
|
||||||
|
UsageCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Members
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (!(obj is TextBlock))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Equals((TextBlock)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Text.GetHashCode() ^ Font.GetHashCode() ^ LayoutRectangle.GetHashCode() ^ Options.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEquatable<TextBlock> Members
|
||||||
|
|
||||||
|
public bool Equals(TextBlock other)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
Text == other.Text &&
|
||||||
|
Font == other.Font &&
|
||||||
|
LayoutRectangle == other.LayoutRectangle &&
|
||||||
|
Options == other.Options;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
24
Source/Utilities/Graphics/Text/TextBlockComparer.cs
Normal file
24
Source/Utilities/Graphics/Text/TextBlockComparer.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
class TextBlockComparer : IComparer<TextBlock>
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public TextBlockComparer() { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IComparer<TextBlock> Members
|
||||||
|
|
||||||
|
public int Compare(TextBlock x, TextBlock y)
|
||||||
|
{
|
||||||
|
return x.UsageCount.CompareTo(y.UsageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
87
Source/Utilities/Graphics/Text/TextExtents.cs
Normal file
87
Source/Utilities/Graphics/Text/TextExtents.cs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics.Text
|
||||||
|
{
|
||||||
|
// Holds layout information about a TextBlock.
|
||||||
|
public struct TextExtents
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
RectangleF text_extents;
|
||||||
|
List<RectangleF> glyph_extents;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public TextExtents(RectangleF bbox)
|
||||||
|
: this(bbox, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextExtents(RectangleF bbox, IEnumerable<RectangleF> glyphExtents)
|
||||||
|
: this()
|
||||||
|
{
|
||||||
|
BoundingBox = bbox;
|
||||||
|
|
||||||
|
if (glyphExtents != null)
|
||||||
|
AddRange(glyphExtents);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Members
|
||||||
|
|
||||||
|
public RectangleF BoundingBox
|
||||||
|
{
|
||||||
|
get { return text_extents; }
|
||||||
|
internal set { text_extents = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public RectangleF this[int i]
|
||||||
|
{
|
||||||
|
get { return (GlyphExtents as List<RectangleF>)[i]; }
|
||||||
|
internal set { (GlyphExtents as List<RectangleF>)[i] = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<RectangleF> GlyphExtents
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (glyph_extents == null)
|
||||||
|
glyph_extents = new List<RectangleF>();
|
||||||
|
return (IEnumerable<RectangleF>)glyph_extents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get { return (GlyphExtents as List<RectangleF>).Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Internal Members
|
||||||
|
|
||||||
|
internal void Add(RectangleF glyphExtent)
|
||||||
|
{
|
||||||
|
(GlyphExtents as List<RectangleF>).Add(glyphExtent);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddRange(IEnumerable<RectangleF> glyphExtents)
|
||||||
|
{
|
||||||
|
(GlyphExtents as List<RectangleF>).AddRange(glyphExtents);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Clear()
|
||||||
|
{
|
||||||
|
BoundingBox = RectangleF.Empty;
|
||||||
|
(GlyphExtents as List<RectangleF>).Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
52
Source/Utilities/Graphics/TextureRegion2D.cs
Normal file
52
Source/Utilities/Graphics/TextureRegion2D.cs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace OpenTK.Graphics
|
||||||
|
{
|
||||||
|
abstract class TextureRegion2D
|
||||||
|
{
|
||||||
|
Rectangle rectangle;
|
||||||
|
|
||||||
|
public Rectangle Rectangle { get { return rectangle; } protected set { rectangle = value; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds part or the whole of a 2d OpenGL texture.
|
||||||
|
/// </summary>
|
||||||
|
class TextureRegion2D<T> : 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,7 +54,7 @@ namespace OpenTK
|
||||||
|
|
||||||
// Tree is full and insertion failed:
|
// Tree is full and insertion failed:
|
||||||
if (node == null)
|
if (node == null)
|
||||||
throw new InvalidOperationException("There is not enough space to add this item. Consider calling the Clear() method.");
|
throw new TexturePackerFullException();
|
||||||
|
|
||||||
//items.Add(item, node);
|
//items.Add(item, node);
|
||||||
rect = node.Rect;
|
rect = node.Rect;
|
||||||
|
@ -193,4 +193,9 @@ namespace OpenTK
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TexturePackerFullException : Exception
|
||||||
|
{
|
||||||
|
public TexturePackerFullException() : base("There is not enough space to add this item. Consider calling the Clear() method.") { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue