2007-11-06 13:29:18 +00:00
|
|
|
|
#region --- License ---
|
2008-05-05 17:13:22 +00:00
|
|
|
|
/* 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.
|
2007-11-06 13:29:18 +00:00
|
|
|
|
*/
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
using System;
|
2007-11-01 23:22:00 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Text.RegularExpressions;
|
2007-11-06 20:59:15 +00:00
|
|
|
|
using System.Runtime.InteropServices;
|
2008-11-24 16:43:56 +00:00
|
|
|
|
using System.Diagnostics;
|
2007-11-01 23:22:00 +00:00
|
|
|
|
|
|
|
|
|
using OpenTK.Math;
|
2008-11-24 16:43:56 +00:00
|
|
|
|
using OpenTK.Graphics;
|
|
|
|
|
using OpenTK.Graphics.Text;
|
|
|
|
|
using OpenTK.Platform;
|
2007-11-01 23:22:00 +00:00
|
|
|
|
|
2008-03-08 14:38:10 +00:00
|
|
|
|
namespace OpenTK.Fonts { }
|
|
|
|
|
|
|
|
|
|
namespace OpenTK.Graphics
|
2007-11-01 23:22:00 +00:00
|
|
|
|
{
|
2007-11-06 13:29:18 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Provides methods to perform layout and print hardware accelerated text.
|
|
|
|
|
/// </summary>
|
2008-11-24 16:43:56 +00:00
|
|
|
|
public sealed class TextPrinter : ITextPrinter
|
2007-11-01 23:22:00 +00:00
|
|
|
|
{
|
2008-11-25 18:00:17 +00:00
|
|
|
|
#region Fields
|
2007-11-12 07:36:34 +00:00
|
|
|
|
|
2008-11-25 18:00:17 +00:00
|
|
|
|
GlyphCache glyph_cache;
|
|
|
|
|
IGlyphRasterizer glyph_rasterizer;
|
|
|
|
|
ITextOutputProvider text_output;
|
2007-11-12 07:36:34 +00:00
|
|
|
|
|
2008-11-25 18:00:17 +00:00
|
|
|
|
float[] viewport = new float[4];
|
2007-11-06 13:29:18 +00:00
|
|
|
|
|
2007-11-12 07:36:34 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
2008-11-25 18:00:17 +00:00
|
|
|
|
#region Constructors
|
2007-11-12 07:36:34 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2008-11-25 18:00:17 +00:00
|
|
|
|
/// Constructs a new TextPrinter object.
|
2007-11-12 07:36:34 +00:00
|
|
|
|
/// </summary>
|
2008-11-25 18:00:17 +00:00
|
|
|
|
public TextPrinter()
|
|
|
|
|
: this(null, null)
|
2007-11-06 13:29:18 +00:00
|
|
|
|
{
|
2008-01-06 02:19:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-25 18:00:17 +00:00
|
|
|
|
TextPrinter(IGlyphRasterizer rasterizer, ITextOutputProvider output/*, IGlyphCacheProvider, ITextOutputProvider */)
|
2008-01-06 02:19:53 +00:00
|
|
|
|
{
|
2008-11-25 18:00:17 +00:00
|
|
|
|
if (rasterizer == null)
|
|
|
|
|
rasterizer = new GdiPlusGlyphRasterizer();
|
2007-11-12 07:36:34 +00:00
|
|
|
|
|
2008-11-25 18:00:17 +00:00
|
|
|
|
if (output == null)
|
|
|
|
|
output = new GL1TextOutputProvider();
|
2008-04-13 18:29:36 +00:00
|
|
|
|
|
2008-11-25 18:00:17 +00:00
|
|
|
|
glyph_rasterizer = rasterizer;
|
|
|
|
|
glyph_cache = new GlyphCache(rasterizer);
|
|
|
|
|
text_output = output;
|
2007-11-12 07:36:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2008-11-25 18:00:17 +00:00
|
|
|
|
#region ITextPrinter Members
|
2007-11-12 07:36:34 +00:00
|
|
|
|
|
|
|
|
|
#region public void Begin()
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets up OpenGL state for drawing text.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Begin()
|
|
|
|
|
{
|
2008-04-13 18:29:36 +00:00
|
|
|
|
if (GraphicsContext.CurrentContext == null)
|
|
|
|
|
throw new GraphicsContextException("No GraphicsContext is current in the calling thread.");
|
|
|
|
|
|
2007-11-12 07:36:34 +00:00
|
|
|
|
GL.GetFloat(GetPName.Viewport, viewport);
|
|
|
|
|
|
|
|
|
|
// Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode,
|
|
|
|
|
// with size equal to the window (in pixels).
|
|
|
|
|
// While we could also render text in 3D mode, it would be very hard to get
|
|
|
|
|
// pixel-perfect precision.
|
|
|
|
|
GL.MatrixMode(MatrixMode.Projection);
|
2007-12-01 16:51:30 +00:00
|
|
|
|
GL.PushMatrix();
|
2007-11-12 07:36:34 +00:00
|
|
|
|
GL.LoadIdentity();
|
2008-02-02 12:29:21 +00:00
|
|
|
|
GL.Ortho(viewport[0], viewport[2], viewport[3], viewport[1], -1.0, 1.0);
|
2007-11-12 07:36:34 +00:00
|
|
|
|
|
|
|
|
|
GL.MatrixMode(MatrixMode.Modelview);
|
2007-12-01 16:51:30 +00:00
|
|
|
|
GL.PushMatrix();
|
2007-11-12 07:36:34 +00:00
|
|
|
|
GL.LoadIdentity();
|
|
|
|
|
|
2008-04-13 18:29:36 +00:00
|
|
|
|
GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit);
|
2007-11-06 13:29:18 +00:00
|
|
|
|
|
2008-01-24 09:16:15 +00:00
|
|
|
|
GL.Enable(EnableCap.Texture2D);
|
2007-11-06 13:29:18 +00:00
|
|
|
|
GL.Enable(EnableCap.Blend);
|
|
|
|
|
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
|
|
|
|
|
|
2007-11-08 15:56:49 +00:00
|
|
|
|
GL.Disable(EnableCap.DepthTest);
|
2007-11-12 07:36:34 +00:00
|
|
|
|
}
|
2007-11-06 20:59:15 +00:00
|
|
|
|
|
2007-11-12 07:36:34 +00:00
|
|
|
|
#endregion
|
2007-11-06 13:29:18 +00:00
|
|
|
|
|
2007-11-12 07:36:34 +00:00
|
|
|
|
#region public void End()
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Restores OpenGL state.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void End()
|
|
|
|
|
{
|
2007-11-06 13:29:18 +00:00
|
|
|
|
GL.PopAttrib();
|
2007-12-01 16:51:30 +00:00
|
|
|
|
|
2008-02-02 12:29:21 +00:00
|
|
|
|
GL.MatrixMode(MatrixMode.Modelview);
|
2007-12-01 16:51:30 +00:00
|
|
|
|
GL.PopMatrix();
|
|
|
|
|
|
2008-02-02 12:29:21 +00:00
|
|
|
|
GL.MatrixMode(MatrixMode.Projection);
|
2007-11-12 07:36:34 +00:00
|
|
|
|
GL.PopMatrix();
|
2007-11-06 13:29:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
2007-11-12 07:36:34 +00:00
|
|
|
|
|
2008-11-24 16:43:56 +00:00
|
|
|
|
#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
|
|
|
|
|
|
2008-11-25 16:11:31 +00:00
|
|
|
|
#region Measure
|
|
|
|
|
|
|
|
|
|
public TextExtents Measure(string text, Font font)
|
|
|
|
|
{
|
|
|
|
|
return Measure(text, font, 0, RectangleF.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TextExtents Measure(string text, Font font, TextPrinterOptions options)
|
|
|
|
|
{
|
|
|
|
|
return Measure(text, font, options, RectangleF.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TextExtents Measure(string text, Font font, TextPrinterOptions options, RectangleF layoutRectangle)
|
|
|
|
|
{
|
|
|
|
|
return glyph_rasterizer.MeasureText(new TextBlock(text, font, options, layoutRectangle));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2008-11-24 16:43:56 +00:00
|
|
|
|
#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
|
2007-11-06 13:29:18 +00:00
|
|
|
|
}
|
2007-11-01 23:22:00 +00:00
|
|
|
|
}
|