Merged text branch and updated changelog.

This commit is contained in:
the_fiddler 2009-02-13 19:09:38 +00:00
parent da7972ad37
commit db690b144f
66 changed files with 3935 additions and 522 deletions

View file

@ -6,10 +6,31 @@ OpenTK 0.9.1 -> 0.9.2
+ OpenTK
+ Platform
+ Added GdiPlus bindings.
+ Fixed a bug where the KeypardEnter key was reported as Enter on X11.
+ Changed the Time X11 struct from int to IntPtr.
+ Improved GLControl implementations.
+ Graphics
+ Added Color4 struct that can hold floating-point ARGB colors.
+ Added several new overloads to the GL class. Most deal with OpenTK.Math and System.Drawing.Color interoperation.
+ Math
+ Added half and double precision structures.
+ Added missing ref overloads.
+ All structs now implement the IEquatable and ISerializable interfaces.
+ General
+ Fixed build warnings.
+ Eliminated per-frame memory allocations in release builds.
+ Utilities
+ Fonts
+ Updated the layout code to use the new GdiPlus bindings.
+ Added support for near-, far- and center-aligned text.
+ Added support for right-to-left and vertical text (not 100% complete).
+ Added support for subpixel antialiasing (requires GL 1.2 or higher).
+ Examples
+ Improved ExampleLauncher behavior on recent Mono/Linux releases.
+ Switched to the new TextPrinter implementation.
+ Changed background color from SteelBlue to MidnightBlue.
---------------------
OpenTK 0.9.0 -> 0.9.1

View file

@ -247,7 +247,7 @@ namespace Examples
//fileIO.Demand();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);
Application.SetCompatibleTextRenderingDefault(false);
using (Form exampleLauncher = new ExampleLauncher())
{
Application.Run(exampleLauncher);

View file

@ -8,6 +8,7 @@
using System;
using System.Diagnostics;
using System.Drawing;
using OpenTK;
using OpenTK.Input;
@ -25,7 +26,7 @@ namespace Examples.Tutorial
{
}
TextureFont sans = new TextureFont(new System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, 14.0f));
Font sans = new Font(System.Drawing.FontFamily.GenericSansSerif, 16.0f);
ITextPrinter text = new TextPrinter();
uint ColorTexture;
@ -236,7 +237,7 @@ namespace Examples.Tutorial
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
text.Begin();
text.Draw((1.0 / e.Time).ToString("F2"), sans);
text.Print((1.0 / e.Time).ToString("F2"), sans, Color.White);
text.End();
GL.PushMatrix();

View file

@ -168,7 +168,7 @@ namespace Examples
new double[] {400.0, 150.0, 0.0, 0.0, 1.0, 0.0}
};
GL.ClearColor(System.Drawing.Color.SteelBlue);
GL.ClearColor(System.Drawing.Color.MidnightBlue);
tess = Glu.NewTess();
startList = GL.GenLists(3);

View file

@ -55,7 +55,7 @@ namespace Examples.Tutorial
// Text drawing (for fps)
TextPrinter printer = new TextPrinter();
TextureFont font = new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f));
Font font = new Font(FontFamily.GenericSansSerif, 16.0f);
#endregion private Fields
@ -289,8 +289,7 @@ namespace Examples.Tutorial
// Then, render the fps:
GL.UseProgram(0);
printer.Begin();
GL.Color3(Color.PaleGoldenrod);
printer.Draw((1 / e.Time).ToString("F2"), font);
printer.Print((1 / e.Time).ToString("F2"), font, Color.PaleGoldenrod, RectangleF.Empty, TextPrinterOptions.NoCache);
printer.End();
SwapBuffers();

View file

@ -20,7 +20,7 @@ namespace Examples.Tests
[Example("GameWindow states", ExampleCategory.Test)]
public class GameWindowStates : GameWindow
{
TextureFont font = new TextureFont(new Font(FontFamily.GenericSansSerif, 16.0f));
Font font = new Font(FontFamily.GenericSansSerif, 16.0f);
TextPrinter printer = new TextPrinter();
#region GetNext and GetPrevious methods for enums.
@ -67,7 +67,7 @@ namespace Examples.Tests
this.Keyboard.KeyRepeat = true;
this.Keyboard.KeyUp += new OpenTK.Input.KeyUpEvent(Keyboard_KeyUp);
GL.ClearColor(System.Drawing.Color.SteelBlue);
GL.ClearColor(System.Drawing.Color.MidnightBlue);
}
void Keyboard_KeyUp(KeyboardDevice sender, Key key)
@ -118,13 +118,14 @@ namespace Examples.Tests
printer.Begin();
printer.Draw("Instructions:", font); GL.Translate(0, font.Height, 0);
printer.Draw(String.Format("1 - cycle through window styles (current: {0}).", this.WindowState), font);
printer.Print("Instructions:", font, Color.White);
GL.Translate(0, font.Height, 0);
printer.Draw(String.Format("2 - cycle through window borders (current: {0}).", this.WindowBorder), font);
printer.Print(String.Format("1 - cycle through window styles (current: {0}).", this.WindowState), font, Color.White, RectangleF.Empty);
GL.Translate(0, font.Height, 0);
printer.Draw(String.Format("3 - toggle fullscreen (current: {0}).",
this.WindowState == WindowState.Fullscreen ? "enabled" : "disabled"), font);
printer.Print(String.Format("2 - cycle through window borders (current: {0}).", this.WindowBorder), font, Color.White, RectangleF.Empty);
GL.Translate(0, font.Height, 0);
printer.Print(String.Format("3 - toggle fullscreen (current: {0}).",
this.WindowState == WindowState.Fullscreen ? "enabled" : "disabled"), font, Color.White, RectangleF.Empty);
printer.End();

View file

@ -33,52 +33,50 @@ namespace Examples.Tutorial
ITextPrinter printer = new TextPrinter();
const string text = "Hello, world!";
TextHandle[] handles; // Used to cache the strings we want to print.
// Load some different TextureFont sizes to compare their quality.
// You'll never need to load that many fonts in your application,
// 3 or 4 should be more than enough.
TextureFont[] fonts = new TextureFont[]
Font[] fonts = new Font[]
{
new TextureFont(new Font(FontFamily.GenericSerif, 8.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 10.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 12.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 14.0f)),
new Font(FontFamily.GenericSerif, 8.0f),
new Font(FontFamily.GenericSerif, 10.0f),
new Font(FontFamily.GenericSerif, 12.0f),
new Font(FontFamily.GenericSerif, 14.0f),
new TextureFont(new Font(FontFamily.GenericSerif, 16.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 18.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 20.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 22.0f)),
new Font(FontFamily.GenericSerif, 16.0f),
new Font(FontFamily.GenericSerif, 18.0f),
new Font(FontFamily.GenericSerif, 20.0f),
new Font(FontFamily.GenericSerif, 22.0f),
new TextureFont(new Font(FontFamily.GenericSerif, 24.0f, FontStyle.Bold)),
new TextureFont(new Font(FontFamily.GenericSerif, 26.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 28.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 30.0f)),
new Font(FontFamily.GenericSerif, 24.0f, FontStyle.Bold),
new Font(FontFamily.GenericSerif, 26.0f),
new Font(FontFamily.GenericSerif, 28.0f),
new Font(FontFamily.GenericSerif, 30.0f),
new TextureFont(new Font(FontFamily.GenericSerif, 32.0f, FontStyle.Italic)),
new TextureFont(new Font(FontFamily.GenericSerif, 34.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 36.0f)),
new TextureFont(new Font(FontFamily.GenericSerif, 38.0f)),
new Font(FontFamily.GenericSerif, 32.0f, FontStyle.Italic),
new Font(FontFamily.GenericSerif, 34.0f),
new Font(FontFamily.GenericSerif, 36.0f),
new Font(FontFamily.GenericSerif, 38.0f),
new TextureFont(new Font(FontFamily.GenericSansSerif, 8.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 10.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 12.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f)),
new Font(FontFamily.GenericSansSerif, 8.0f),
new Font(FontFamily.GenericSansSerif, 10.0f),
new Font(FontFamily.GenericSansSerif, 12.0f),
new Font(FontFamily.GenericSansSerif, 14.0f),
new TextureFont(new Font(FontFamily.GenericSansSerif, 16.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 18.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 20.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 22.0f)),
new Font(FontFamily.GenericSansSerif, 16.0f),
new Font(FontFamily.GenericSansSerif, 18.0f),
new Font(FontFamily.GenericSansSerif, 20.0f),
new Font(FontFamily.GenericSansSerif, 22.0f),
new TextureFont(new Font(FontFamily.GenericSansSerif, 24.0f, FontStyle.Bold)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 26.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 28.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 30.0f)),
new Font(FontFamily.GenericSansSerif, 24.0f, FontStyle.Bold),
new Font(FontFamily.GenericSansSerif, 26.0f),
new Font(FontFamily.GenericSansSerif, 28.0f),
new Font(FontFamily.GenericSansSerif, 30.0f),
new TextureFont(new Font(FontFamily.GenericSansSerif, 32.0f, FontStyle.Italic)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 34.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 36.0f)),
new TextureFont(new Font(FontFamily.GenericSansSerif, 38.0f)),
new Font(FontFamily.GenericSansSerif, 32.0f, FontStyle.Italic),
new Font(FontFamily.GenericSansSerif, 34.0f),
new Font(FontFamily.GenericSansSerif, 36.0f),
new Font(FontFamily.GenericSansSerif, 38.0f),
};
#endregion
@ -98,11 +96,7 @@ namespace Examples.Tutorial
/// <param name="e"></param>
public override void OnLoad(EventArgs e)
{
GL.ClearColor(Color.SteelBlue);
handles = new TextHandle[fonts.Length];
for (int i = handles.Length; --i >= 0; )
printer.Prepare(text, fonts[i], out handles[i]);
GL.ClearColor(Color.MidnightBlue);
}
#endregion
@ -117,9 +111,7 @@ namespace Examples.Tutorial
/// <param name="e"></param>
public override void OnUnload(EventArgs e)
{
foreach (TextHandle h in handles)
h.Dispose();
foreach (TextureFont f in fonts)
foreach (Font f in fonts)
f.Dispose();
}
@ -168,21 +160,21 @@ namespace Examples.Tutorial
printer.Begin();
// Print using the first font.
for (int i = 0; i < handles.Length / 2; i++)
for (int i = 0; i < fonts.Length / 2; i++)
{
printer.Draw(handles[i]);
printer.Print(text, fonts[i], Color.White);
GL.Translate(0, fonts[i].Height, 0);
}
// Move to the right, and print using the second font.
//float width, height;
//fonts[handles.Length / 2 - 1].MeasureString(text, out width, out height);
RectangleF rect = fonts[handles.Length / 2 - 1].MeasureText(text);
RectangleF rect = printer.Measure(text, fonts[fonts.Length / 2 - 1]).BoundingBox;
GL.LoadIdentity();
GL.Translate(rect.Width + 32.0f, 0, 0);
for (int i = handles.Length / 2; i < handles.Length; i++)
for (int i = fonts.Length / 2; i < fonts.Length; i++)
{
printer.Draw(handles[i]);
printer.Print(text, fonts[i], Color.White);
GL.Translate(0, fonts[i].Height, 0);
}

View file

@ -58,7 +58,7 @@ namespace Examples.Tutorial
/// <param name="e">Not used.</param>
public override void OnLoad(EventArgs e)
{
GL.ClearColor(Color.SteelBlue);
GL.ClearColor(Color.MidnightBlue);
}
#endregion
@ -110,7 +110,7 @@ namespace Examples.Tutorial
GL.Begin(BeginMode.Triangles);
GL.Color3(Color.LightSteelBlue);
GL.Color3(Color.MidnightBlue);
GL.Vertex2(-1.0f, 1.0f);
GL.Color3(Color.SpringGreen);
GL.Vertex2(0.0f, -1.0f);

View file

@ -48,7 +48,7 @@ namespace Examples.Tutorial
{
base.OnLoad(e);
GL.ClearColor(Color.SteelBlue);
GL.ClearColor(Color.MidnightBlue);
GL.Enable(EnableCap.DepthTest);
}

View file

@ -45,7 +45,7 @@ namespace Examples.Tutorial
public override void OnLoad(EventArgs e)
{
GL.ClearColor(Color.SteelBlue);
GL.ClearColor(Color.MidnightBlue);
GL.Enable(EnableCap.DepthTest);
GL.MatrixMode(MatrixMode.Modelview);

View file

@ -68,7 +68,7 @@ namespace Examples.Tutorial
this.Exit();
}
GL.ClearColor(Color.SteelBlue);
GL.ClearColor(Color.MidnightBlue);
GL.Enable(EnableCap.DepthTest);
CreateVBO();

View file

@ -23,10 +23,9 @@ namespace Examples.Tutorial
[Example("Text", ExampleCategory.Tutorial, 4)]
public class Text : GameWindow
{
TextureFont serif = new TextureFont(new Font(FontFamily.GenericSerif, 24.0f));
TextureFont sans = new TextureFont(new Font(FontFamily.GenericSansSerif, 14.0f));
TextHandle poem_handle;
ITextPrinter text = new TextPrinter();
Font serif = new Font(FontFamily.GenericSerif, 16.0f);
Font sans = new Font(FontFamily.GenericSansSerif, 18.0f);
TextPrinter text = new TextPrinter();
string poem = new StreamReader("Data/Poem.txt").ReadToEnd();
int lines; // How many lines the poem contains.
@ -44,11 +43,10 @@ namespace Examples.Tutorial
public override void OnLoad(EventArgs e)
{
GL.ClearColor(Color.SteelBlue);
GL.ClearColor(Color.MidnightBlue);
current_position = initial_position;
scroll_speed = -1.0f;
text.Prepare(poem, serif, out poem_handle);
// Count the amount of lines in the text, to find out the correct
// warparound position. We want the text to scroll until the last
@ -58,8 +56,7 @@ namespace Examples.Tutorial
if (c == '\n')
lines++;
warparound_position =
-(lines + 1) * serif.Height;
warparound_position = -(lines + 1) * serif.Height;
}
#endregion
@ -68,8 +65,10 @@ namespace Examples.Tutorial
public override void OnUnload(EventArgs e)
{
if (poem_handle != null) poem_handle.Dispose();
if (serif != null) serif.Dispose();
if (serif != null)
serif.Dispose();
if (sans != null)
sans.Dispose();
}
#endregion
@ -81,9 +80,7 @@ namespace Examples.Tutorial
GL.Viewport(0, 0, Width, Height);
initial_position = Height + serif.Height; // Start one line below the screen.
warparound_position =
-(lines + 1) * serif.Height;
warparound_position = -(lines + 1) * serif.Height;
}
#endregion
@ -93,11 +90,11 @@ namespace Examples.Tutorial
public override void OnUpdateFrame(UpdateFrameEventArgs e)
{
if (Keyboard[Key.Space])
scroll_speed = 0.0f;
scroll_speed = 0;
if (Keyboard[Key.Down])
scroll_speed += 1;
scroll_speed += 10;
if (Keyboard[Key.Up])
scroll_speed -= 1;
scroll_speed -= 10;
if (Keyboard[Key.Escape])
this.Exit();
}
@ -113,7 +110,7 @@ namespace Examples.Tutorial
// We'll start printing from the lower left corner of the screen. The text
// will slowly move updwards - the user can control the movement speed with
// the keyboard arrows and the space bar.
current_position += scroll_speed * (float)e.ScaleFactor;
current_position += scroll_speed * (float)e.Time;
if (scroll_speed > 0.0f && current_position > initial_position)
current_position = warparound_position;
else if (scroll_speed < 0.0f && current_position < warparound_position)
@ -125,11 +122,16 @@ namespace Examples.Tutorial
// used in 2d graphics, and is necessary for achieving pixel-perfect glyph rendering.
// TextPrinter.End() restores your previous projection/modelview matrices.
text.Begin();
GL.Color3(Color.LightBlue);
text.Draw((1.0 / e.Time).ToString("F2"), sans);
GL.Translate(0.0f, current_position, 0.0f);
GL.Color3(Color.White);
text.Draw(poem_handle);
// Print FPS counter. Since the counter changes per frame,
// it shouldn't be cached (TextPrinterOptions.NoCache).
text.Print((1.0 / e.Time).ToString("F2"), sans, Color.SpringGreen, new RectangleF(0, 0, Width, 0), TextPrinterOptions.NoCache, TextAlignment.Far);
// Print the actual text.
GL.Translate(0, current_position, 0);
text.Print(poem, serif, Color.White, new RectangleF(Width / 2, 0, Width / 2, 0), TextPrinterOptions.Default, TextAlignment.Far);
text.Print(poem, serif, Color.White, new RectangleF(0, 0, Width / 2, 0));
text.End();
SwapBuffers();

View file

@ -39,7 +39,7 @@ namespace Examples.Tutorial
/// <param name="e">Not used.</param>
public override void OnLoad(EventArgs e)
{
GL.ClearColor(Color.SteelBlue);
GL.ClearColor(Color.MidnightBlue);
GL.Enable(EnableCap.Texture2D);
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);

View file

@ -0,0 +1,96 @@
namespace Examples.WinForms
{
partial class FontRendering
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.glControl1 = new OpenTK.GLControl();
this.changeFont = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.fontDialog = new System.Windows.Forms.FontDialog();
this.SuspendLayout();
//
// glControl1
//
this.glControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.glControl1.BackColor = System.Drawing.Color.Black;
this.glControl1.Location = new System.Drawing.Point(0, 40);
this.glControl1.Name = "glControl1";
this.glControl1.Size = new System.Drawing.Size(700, 521);
this.glControl1.TabIndex = 0;
this.glControl1.VSync = false;
this.glControl1.Load += new System.EventHandler(this.glControl1_Load);
this.glControl1.Paint += new System.Windows.Forms.PaintEventHandler(this.glControl1_Paint);
this.glControl1.Resize += new System.EventHandler(this.glControl1_Resize);
//
// changeFont
//
this.changeFont.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.changeFont.Location = new System.Drawing.Point(568, 10);
this.changeFont.Name = "changeFont";
this.changeFont.Size = new System.Drawing.Size(120, 23);
this.changeFont.TabIndex = 1;
this.changeFont.Text = "Change Font";
this.changeFont.UseVisualStyleBackColor = true;
this.changeFont.Click += new System.EventHandler(this.changeFont_Click);
//
// textBox1
//
this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textBox1.Location = new System.Drawing.Point(12, 11);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(550, 22);
this.textBox1.TabIndex = 2;
this.textBox1.Text = "The quick brown fox jumped over the lazy dogs. 0123456789";
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
//
// FontRendering
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(700, 561);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.changeFont);
this.Controls.Add(this.glControl1);
this.Name = "FontRendering";
this.Text = "FontRendering";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private OpenTK.GLControl glControl1;
private System.Windows.Forms.Button changeFont;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.FontDialog fontDialog;
}
}

View file

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OpenTK.Graphics;
namespace Examples.WinForms
{
[Example("Font rendering sample", ExampleCategory.WinForms)]
public partial class FontRendering : Form
{
#region Fields
//float[] sizes = new float[] { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 28, 32, 36, 42, 48 };
float[] sizes = new float[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 24 };
List<Font> fonts = new List<Font>();
TextPrinter printer = new TextPrinter();
#endregion
#region Constructors
public FontRendering()
{
InitializeComponent();
ResizeRedraw = true;
UpdateFontList(fontDialog.Font);
glControl1_Resize(this, EventArgs.Empty);
}
#endregion
#region Private Members
void UpdateFontList(Font base_font)
{
printer.Clear();
foreach (Font font in fonts)
font.Dispose();
fonts.Clear();
foreach (float size in sizes)
fonts.Add(new Font(base_font.Name, base_font.SizeInPoints + size, base_font.Style));
}
#endregion
#region Events
private void glControl1_Load(object sender, EventArgs e)
{
glControl1.MakeCurrent();
}
private void changeFont_Click(object sender, EventArgs e)
{
if (fontDialog.ShowDialog() == DialogResult.OK)
{
UpdateFontList(fontDialog.Font);
glControl1.Invalidate();
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
glControl1.Invalidate();
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
glControl1.MakeCurrent();
GL.ClearColor(Color.MidnightBlue);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, glControl1.ClientSize.Width, glControl1.ClientSize.Height, 0, -1, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
foreach (Font font in fonts)
{
printer.Print(textBox1.Text, font, Color.White);
GL.Translate(0, font.Height + 5, 0);
}
glControl1.SwapBuffers();
}
private void glControl1_Resize(object sender, EventArgs e)
{
glControl1.MakeCurrent();
if (glControl1.ClientSize.Height == 0)
glControl1.ClientSize = new System.Drawing.Size(glControl1.ClientSize.Width, 1);
GL.Viewport(0, 0, glControl1.ClientSize.Width, glControl1.ClientSize.Height);
}
#endregion
#region public static void Main()
/// <summary>
/// Entry point of this example.
/// </summary>
[STAThread]
public static void Main()
{
using (FontRendering example = new FontRendering())
{
Utilities.SetWindowTitle(example);
example.ShowDialog();
}
}
#endregion
}
}

View file

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="fontDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View file

@ -59,6 +59,8 @@ namespace Examples.WinForms
private void glControl1_Paint(object sender, PaintEventArgs e)
{
glControl1.MakeCurrent();
GL.Clear(ClearBufferMask.ColorBufferBit);
glControl1.SwapBuffers();
}

View file

@ -53,7 +53,7 @@ namespace Examples.WinForms
GL.GetString(StringName.Renderer) + " " +
GL.GetString(StringName.Version);
GL.ClearColor(Color.SteelBlue);
GL.ClearColor(Color.MidnightBlue);
GL.Enable(EnableCap.DepthTest);
Application.Idle += Application_Idle;

View file

@ -62,6 +62,10 @@ namespace OpenTK
Type t = Type.GetType("Mono.Runtime");
if (t != null)
runningOnMono = true;
Debug.Print("Detected configuration: {0} / {1}",
RunningOnWindows ? "Windows" : RunningOnLinux ? "Linux" : RunningOnOSX ? "MacOS" : RunningOnX11 ? "X11" : "Unknown Platform",
RunningOnMono ? "Mono" : ".Net");
}
#endregion

View file

@ -659,6 +659,15 @@ namespace OpenTK.Graphics
#endregion
#region public static void BlendColor() overloads
public static void BlendColor(System.Drawing.Color color)
{
GL.BlendColor(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f);
}
#endregion
#region public static void Material() overloads
public static void Materialv(MaterialFace face, MaterialParameter pname, Vector4 @params)

View file

@ -26,10 +26,10 @@ namespace OpenTK.Platform
static GdiPlus()
{
if (Configuration.RunningOnWindows)
if (Configuration.RunningOnWindows && !Configuration.RunningOnMono)
internals = new Windows.WinGdiPlusInternals();
else
internals = new X11.X11GdiPlusInternals();
internals = new X11.X11GdiPlusInternals(); // This class is Mono-specific and works on all platforms.
}
#endregion

View file

@ -470,11 +470,8 @@ namespace OpenTK.Platform.Windows
#region SwapBuffers
/// <summary>
///
/// </summary>
/// <param name="dc"></param>
[DllImport("gdi32.dll")]
[SuppressUnmanagedCodeSecurity]
[DllImport("gdi32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SwapBuffers(IntPtr dc);

View file

@ -140,8 +140,8 @@ namespace OpenTK.Platform.Windows
public void SwapBuffers()
{
Functions.SwapBuffers(currentWindow.DeviceContext);
if (!Functions.SwapBuffers(currentWindow.DeviceContext))
Debug.Print("SwapBuffers failed, error: {0}", Marshal.GetLastWin32Error());
}
#endregion

View file

@ -14,6 +14,8 @@ using System.Reflection;
namespace OpenTK.Platform.X11
{
// Note: This class is Mono-specific, not X11-specific!
// It works on all platforms (windows, linux, macos) as long as we are running on Mono.
class X11GdiPlusInternals : IGdiPlusInternals
{
static readonly PropertyInfo native_graphics_property, native_font_property, native_string_format_property;

View file

@ -11,6 +11,7 @@ using OpenTK.Graphics.OpenGL;
namespace OpenTK.Graphics
{
[Obsolete()]
class DisplayListTextHandle : TextHandle
{
public DisplayListTextHandle(int handle) : base(handle) { }

View file

@ -16,6 +16,7 @@ namespace OpenTK.Graphics
/// <summary>
/// Provides text printing through OpenGL 1.1 Display Lists.
/// </summary>
[Obsolete()]
class DisplayListTextPrinter : ITextPrinterImplementation
{
#region IPrinter Members

View file

@ -16,6 +16,7 @@ namespace OpenTK.Graphics
/// <summary>
/// Represents a single character of a specific Font.
/// </summary>
[Obsolete]
struct Glyph : IPackable<Glyph>
{
char character;
@ -111,12 +112,29 @@ namespace OpenTK.Graphics
/// <returns>A System.Int32 containing a hashcode that uniquely identifies this Glyph.</returns>
public override int GetHashCode()
{
//return character.GetHashCode() ^ font.Style.GetHashCode() ^ font.Size.GetHashCode() ^ font.Unit.GetHashCode();
return character.GetHashCode() ^ font.GetHashCode() ^ size.GetHashCode();
}
#endregion
#region public SizeF Size
/// <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
#region --- IPackable<T> Members ---
@ -154,7 +172,7 @@ namespace OpenTK.Graphics
/// <returns>True if both Glyphs represent the same character of the same Font, false otherwise.</returns>
public bool Equals(Glyph other)
{
return Character == other.Character && Font == other.Font;
return Character == other.Character && Font == other.Font && Size == other.Size;
}
#endregion

View file

@ -15,6 +15,7 @@ namespace OpenTK.Graphics
/// <summary>
/// Defines the interface for TextPrinter implementations.
/// </summary>
[Obsolete("Use ITextOutputProvider instead")]
public interface ITextPrinterImplementation
{
/// <summary>

View file

@ -1,28 +0,0 @@
#region --- License ---
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* See license.txt for license info
*/
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace OpenTK.Graphics
{
/// <summary>
/// Defines the interface for a TextPrinter.
/// </summary>
public interface ITextPrinter
{
void Prepare(string text, TextureFont font, out TextHandle handle);
void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp);
void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment);
void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment, bool rightToLeft);
void Draw(TextHandle handle);
void Draw(string text, TextureFont font);
void Begin();
void End();
}
}

View file

@ -13,17 +13,27 @@ namespace OpenTK.Graphics
/// <summary>
/// Represents a handle to cached text.
/// </summary>
public abstract class TextHandle : IDisposable
[Obsolete("Use TextPrinter.Print instead")]
public class TextHandle : IDisposable
{
internal string Text;
internal System.Drawing.Font GdiPFont;
/// <summary>
/// Constructs a new TextHandle,
/// </summary>
/// <param name="handle"></param>
public TextHandle(int handle)
internal TextHandle(int handle)
{
Handle = handle;
}
internal TextHandle(string text, System.Drawing.Font font)
{
Text = text;
GdiPFont = font;
}
private int handle;
protected TextureFont font;
protected bool disposed;

View file

@ -1,363 +0,0 @@
#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 OpenTK.Math;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics.OpenGL.Enums;
using System.Diagnostics;
namespace OpenTK.Fonts { }
namespace OpenTK.Graphics
{
/// <summary>
/// Provides methods to perform layout and print hardware accelerated text.
/// </summary>
public class TextPrinter : ITextPrinter
{
//static Regex break_point = new Regex("[ .,/*-+?\\!=]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
//static char[] split_chars = new char[]
//{
// ' ', '\n', '\t', ',', '.', '/', '?', '!', ';', '\\', '-', '+', '*', '='
//};
static ITextPrinterImplementation printer;
float[] viewport = new float[4];
// Interleaved, vertex, texcoord, vertex, etc... Starts with 8 chars, will expand as needed.
Vector2[] vertices = new Vector2[8 * 8];
ushort[] indices = new ushort[6 * 8];
List<RectangleF> ranges = new List<RectangleF>();
#region --- Constructors ---
/// <summary>
/// Constructs a new TextPrinter object.
/// </summary>
public TextPrinter() { }
public TextPrinter(ITextPrinterImplementation implementation)
{
if (implementation == null)
throw new ArgumentNullException("implementation");
printer = implementation;
}
#endregion
#region --- Private Members ---
#region static ITextPrinterImplementation Printer
/// <summary>
/// Checks the machine's capabilities and selects the fastest method to print text.
/// </summary>
static ITextPrinterImplementation Printer
{
get
{
if (printer == null)
{
printer = (ITextPrinterImplementation)new DisplayListTextPrinter();
//GL.SupportsExtension("VERSION_1_5") ?
//(ITextPrinterImplementation)new VboTextPrinter() :
//GL.SupportsExtension("ARB_vertex_buffer_object") ? null :
//GL.SupportsExtension("VERSION_1_1") ? null : null;
if (printer == null)
throw new NotSupportedException("TextPrinter requires at least OpenGL 1.1 support.");
Debug.Print("Using {0} for font printing.", printer);
}
return printer;
}
}
#endregion
#endregion
#region --- ITextPrinter Members ---
#region public void Prepare(string text, TextureFont font, out TextHandle handle)
/// <summary>
/// Prepares text for drawing.
/// </summary>
/// <param name="text">The string to draw.</param>
/// <param name="font">The font to use for drawing.</param>
/// <param name="handle">The handle to the cached text. Use this to draw the text with the Draw() function.</param>
/// <see cref="TextPrinter.Draw()"/>
public void Prepare(string text, TextureFont font, out TextHandle handle)
{
this.Prepare(text, font, out handle, 0, false, StringAlignment.Near, false);
}
#endregion
#region public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp)
/// <summary>
/// Prepares text for drawing.
/// </summary>
/// <param name="text">The string to draw.</param>
/// <param name="font">The font to use for drawing.</param>
/// <param name="handle">The handle to the cached text. Use this to draw the text with the Draw() function.</param>
/// <param name="width">Not implemented.</param>
/// <param name="wordWarp">Not implemented.</param>
/// <see cref="TextPrinter.Draw()"/>
public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp)
{
this.Prepare(text, font, out handle, width, wordWarp, StringAlignment.Near, false);
}
#endregion
#region public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment)
/// <summary>
/// Prepares text for drawing.
/// </summary>
/// <param name="text">The string to draw.</param>
/// <param name="font">The font to use for drawing.</param>
/// <param name="handle">The handle to the cached text. Use this to draw the text with the Draw() function.</param>
/// <param name="width">Not implemented.</param>
/// <param name="wordWarp">Not implemented.</param>
/// <param name="alignment">Not implemented.</param>
/// <see cref="TextPrinter.Draw()"/>
public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment)
{
this.Prepare(text, font, out handle, width, wordWarp, alignment, false);
}
#endregion
#region public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment, bool rightToLeft)
/// <summary>
/// Prepares text for drawing.
/// </summary>
/// <param name="text">The string to draw.</param>
/// <param name="font">The font to use for drawing.</param>
/// <param name="handle">The handle to the cached text. Use this to draw the text with the Draw() function.</param>
/// <param name="width">Not implemented.</param>
/// <param name="wordWarp">Not implemented.</param>
/// <param name="alignment">Not implemented.</param>
/// <param name="rightToLeft">Not implemented.</param>
/// <see cref="TextPrinter.Draw()"/>
/// <exception cref="NotSupportedException">Occurs when OpenGL 1.1 is not supported.</exception>
public void Prepare(string text, TextureFont font, out TextHandle handle, float width, bool wordWarp, StringAlignment alignment, bool rightToLeft)
{
int num_indices;
PerformLayout(text, font, width, wordWarp, alignment, rightToLeft, ref vertices, ref indices, out num_indices);
handle = Printer.Load(vertices, indices, num_indices);
handle.Font = font;
}
#endregion
#region void PerformLayout(string text, TextureFont font, float width, bool wordWarp, StringAlignment alignment, bool rightToLeft, ref Vector2[] vertices, ref ushort[] indices, out int num_indices)
// Performs layout on the given string.
void PerformLayout(string text, TextureFont font, float width, bool wordWarp, StringAlignment alignment,
bool rightToLeft, ref Vector2[] vertices, ref ushort[] indices, out int num_indices)
{
if (text == null)
throw new ArgumentNullException("Parameter cannot be null.", "text");
if (text.Length > 8192)
throw new ArgumentOutOfRangeException("text", text.Length, "Text length must be between 1 and 8192 characters");
if (wordWarp || rightToLeft || alignment != StringAlignment.Near)
throw new NotImplementedException();
if (8 * text.Length > vertices.Length)
vertices = new Vector2[Math.Functions.NextPowerOfTwo(8 * text.Length)];
if (6 * text.Length > indices.Length)
indices = new ushort[Math.Functions.NextPowerOfTwo(6 * text.Length)];
num_indices = 6 * text.Length;
//Vector2[] vertices = new Vector2[8 * text.Length]; // Interleaved, vertex, texcoord, vertex, etc...
//ushort[] indices = new ushort[6 * text.Length];
float x_pos = 0, y_pos = 0;
ushort i = 0, index_count = 0, vertex_count = 0;
RectangleF rect = new RectangleF();
float char_width, char_height;
int texture;
font.LoadGlyphs(text);
// Every character comprises of 4 vertices, forming two triangles. We generate an index array which
// indexes vertices in a triangle-list fashion.
// This algorithm works for left-to-right scripts.
if (alignment == StringAlignment.Near && !rightToLeft || alignment == StringAlignment.Far && rightToLeft)
{
font.MeasureText(text, SizeF.Empty, null, ranges);
int current = 0;
foreach (char c in text)
{
if (c == '\n' || c == '\r')
continue;
else if (Char.IsWhiteSpace(c))
{
current++;
continue;
}
RectangleF range = ranges[current++];
x_pos = range.X;
y_pos = range.Y;
font.GlyphData(c, out char_width, out char_height, out rect, out texture);
vertices[vertex_count].X = x_pos; // Vertex
vertices[vertex_count++].Y = y_pos;
vertices[vertex_count].X = rect.Left; // Texcoord
vertices[vertex_count++].Y = rect.Top;
vertices[vertex_count].X = x_pos; // Vertex
vertices[vertex_count++].Y = y_pos + char_height;
vertices[vertex_count].X = rect.Left; // Texcoord
vertices[vertex_count++].Y = rect.Bottom;
vertices[vertex_count].X = x_pos + char_width; // Vertex
vertices[vertex_count++].Y = y_pos + char_height;
vertices[vertex_count].X = rect.Right; // Texcoord
vertices[vertex_count++].Y = rect.Bottom;
vertices[vertex_count].X = x_pos + char_width; // Vertex
vertices[vertex_count++].Y = y_pos;
vertices[vertex_count].X = rect.Right; // Texcoord
vertices[vertex_count++].Y = rect.Top;
indices[index_count++] = (ushort)(vertex_count - 8);
indices[index_count++] = (ushort)(vertex_count - 6);
indices[index_count++] = (ushort)(vertex_count - 4);
indices[index_count++] = (ushort)(vertex_count - 4);
indices[index_count++] = (ushort)(vertex_count - 2);
indices[index_count++] = (ushort)(vertex_count - 8);
++i;
}
}
else if (alignment != StringAlignment.Center)
{
throw new NotImplementedException("This feature is not yet implemented. Sorry for the inconvenience.");
}
else
{
throw new NotImplementedException("This feature is not yet implemented. Sorry for the inconvenience.");
}
}
#endregion
#region public void Draw(TextHandle handle)
/// <summary>
/// Draws the cached text referred to by the TextHandle.
/// </summary>
/// <param name="handle">The TextHandle to the cached text.</param>
public void Draw(TextHandle handle)
{
GL.BindTexture(TextureTarget.Texture2D, handle.Font.Texture);
Printer.Draw(handle);
}
#endregion
#region public void Draw(string text, TextureFont font)
/// <summary>
/// Draws dynamic text without caching. Not implemented yet!
/// </summary>
/// <param name="text">The System.String to draw.</param>
/// <param name="font">The OpenTK.Graphics.TextureFont to draw the text in.</param>
public void Draw(string text, TextureFont font)
{
int num_indices;
PerformLayout(text, font, 0, false, StringAlignment.Near, false, ref vertices, ref indices, out num_indices);
GL.BindTexture(TextureTarget.Texture2D, font.Texture);
Printer.Draw(vertices, indices, num_indices);
}
#endregion
#region public void Begin()
/// <summary>
/// Sets up OpenGL state for drawing text.
/// </summary>
public void Begin()
{
if (GraphicsContext.CurrentContext == null)
throw new GraphicsContextException("No GraphicsContext is current in the calling thread.");
GL.GetFloat(GetPName.Viewport, viewport);
// Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode,
// with size equal to the window (in pixels).
// While we could also render text in 3D mode, it would be very hard to get
// pixel-perfect precision.
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.Ortho(viewport[0], viewport[2], viewport[3], viewport[1], -1.0, 1.0);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit);
GL.Enable(EnableCap.Texture2D);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.Disable(EnableCap.DepthTest);
}
#endregion
#region public void End()
/// <summary>
/// Restores OpenGL state.
/// </summary>
public void End()
{
GL.PopAttrib();
GL.MatrixMode(MatrixMode.Modelview);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
}
#endregion
#endregion
}
}

View file

@ -21,11 +21,12 @@ namespace OpenTK.Graphics
{
using Graphics = System.Drawing.Graphics;
using PixelFormat = OpenTK.Graphics.PixelFormat;
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
[Obsolete("Use System.Drawing.Font instead")]
public class TextureFont : IFont
{
Font font;
internal Font font;
Dictionary<char, RectangleF> loaded_glyphs = new Dictionary<char, RectangleF>(64);
Bitmap bmp;

View file

@ -17,6 +17,7 @@ namespace OpenTK.Graphics
/// <summary>
/// Provides text printing through OpenGL 1.5 vertex buffer objects.
/// </summary>
[Obsolete]
class VboTextPrinter : ITextPrinterImplementation
{
static int allocated_handles;
@ -84,6 +85,7 @@ namespace OpenTK.Graphics
/// <summary>
/// Contains the necessary information to print text through the VboTextPrinter implementation.
/// </summary>
[Obsolete]
class VboTextHandle : TextHandle
{
public VboTextHandle(int handle) : base(handle) { }

View file

@ -0,0 +1,61 @@
#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace OpenTK.Graphics
{
/// <summary>
/// Encapsulates an OpenGL texture.
/// </summary>
class AlphaTexture2D : Texture2D
{
#region Constructors
/// <summary>
/// Constructs a new Texture.
/// </summary>
public AlphaTexture2D(int width, int height)
: base(width, height)
{ }
#endregion
#region Protected Members
protected override PixelInternalFormat InternalFormat
{
get { return PixelInternalFormat.Alpha; }
}
#endregion
}
}

View file

@ -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
{
/// <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) { }
}
}

View file

@ -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
{
/// <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; }
}
}

View file

@ -0,0 +1,162 @@
#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
{
/// <summary>
/// Defines the interface for a TextPrinter.
/// </summary>
public interface ITextPrinter : IDisposable
{
#region Print
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
void Print(string text, Font font, Color color);
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
void Print(string text, Font font, Color color, RectangleF rect);
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to print text.</param>
void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options);
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to print text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to print text.</param>
void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment);
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to print text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to print text.</param>
/// <param name="direction">The OpenTK.Graphics.TextDirection that will be used to print text.</param>
void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction);
#endregion
#region Measure
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
TextExtents Measure(string text, Font font);
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to measure text.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
TextExtents Measure(string text, Font font, RectangleF rect);
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to measure text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to measure text.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options);
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to measure text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to measure text.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment);
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to measure text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to measure text.</param>
/// <param name="direction">The OpenTK.Graphics.TextDirection that will be used to measure text.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment, TextDirection direction);
#endregion
#region Begin
/// <summary>
/// Sets up a resolution-dependent orthographic projection.
/// </summary>
void Begin();
#endregion
/// <summary>
/// Restores the projection and modelview matrices to their previous state.
/// </summary>
#region End
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
}
}

View file

@ -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;
namespace OpenTK.Graphics
{
class RgbaTexture2D : Texture2D
{
public RgbaTexture2D(int width, int height)
: base(width, height)
{ }
protected override PixelInternalFormat InternalFormat
{
get { return PixelInternalFormat.Rgba; }
}
}
}

View file

@ -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);
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace OpenTK.Graphics.Text
{
sealed class GL11TextOutputProvider : GL1TextOutputProvider
{
#region Fields
TextQuality quality;
GlyphCache cache;
#endregion
#region Constuctors
public GL11TextOutputProvider(TextQuality quality)
{
if (quality == TextQuality.High || quality == TextQuality.Default)
this.quality = TextQuality.Medium;
else
this.quality = quality;
cache = new GlyphCache<AlphaTexture2D>();
}
#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 { return cache; }
}
#endregion
}
}

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace OpenTK.Graphics.Text
{
sealed class GL12TextOutputProvider : GL1TextOutputProvider
{
#region Fields
TextQuality quality;
GlyphCache cache;
#endregion
#region Constuctors
public GL12TextOutputProvider(TextQuality quality)
{
this.quality = quality;
cache = new GlyphCache<RgbaTexture2D>();
}
#endregion
protected override void SetBlendFunction()
{
GL.BlendFunc(BlendingFactorSrc.ConstantColorExt, BlendingFactorDest.OneMinusSrcColor);
}
protected override void SetColor(Color color)
{
GL.BlendColor(color);
}
protected override TextQuality TextQuality
{
get { return quality; }
}
protected override GlyphCache Cache
{
get { return cache; }
}
}
}

View file

@ -0,0 +1,268 @@
#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.Collections.Generic;
using System.Drawing;
using OpenTK.Math;
using System;
namespace OpenTK.Graphics.Text
{
abstract class GL1TextOutputProvider : ITextOutputProvider
{
#region Fields
// Triangle lists, sorted by texture.
Dictionary<Texture2D, List<Vector2>> active_lists = new Dictionary<Texture2D, List<Vector2>>();
Queue<List<Vector2>> inactive_lists = new Queue<List<Vector2>>();
#pragma warning disable 0649
struct Viewport { public float Left, Top, Right, Bottom; }
#pragma warning restore 0649
bool disposed;
#endregion
#region Constructors
public GL1TextOutputProvider()
{
inactive_lists.Enqueue(new List<Vector2>());
}
#endregion
#region ITextOutputProvider Members
#region Print
public void Print(TextBlock block, Color color, IGlyphRasterizer rasterizer)
{
GL.PushAttrib(AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.DepthBufferBit);
GL.Enable(EnableCap.Texture2D);
GL.Enable(EnableCap.Blend);
SetBlendFunction();
GL.Disable(EnableCap.DepthTest);
using (TextExtents extents = rasterizer.MeasureText(block))
{
// Build layout
int current = 0;
foreach (Glyph glyph in block)
{
if (glyph.IsWhiteSpace)
{
current++;
continue;
}
else if (!Cache.Contains(glyph))
Cache.Add(glyph, rasterizer, TextQuality);
CachedGlyphInfo info = Cache[glyph];
RectangleF position = extents[current++];
// Use the real glyph width instead of the measured one (we want to achieve pixel perfect output).
position.Size = info.Rectangle.Size;
if (!active_lists.ContainsKey(info.Texture))
if (inactive_lists.Count > 0)
active_lists.Add(info.Texture, inactive_lists.Dequeue());
else
active_lists.Add(info.Texture, new List<Vector2>());
{
// Interleaved array: Vertex, TexCoord, Vertex, ...
active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top));
active_lists[info.Texture].Add(new Vector2(position.Left, position.Top));
active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom));
active_lists[info.Texture].Add(new Vector2(position.Left, position.Bottom));
active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom));
active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom));
active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom));
active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom));
active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Top));
active_lists[info.Texture].Add(new Vector2(position.Right, position.Top));
active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top));
active_lists[info.Texture].Add(new Vector2(position.Left, position.Top));
}
}
}
// Render
foreach (Texture2D key in active_lists.Keys)
{
List<Vector2> list = active_lists[key];
key.Bind();
//if (!legacy_mode)
//{
// GL.PushMatrix();
// GL.GetFloat(GetPName.Viewport, viewport);
// GL.Scale(2.0 / (viewport[2] - viewport[0]), -2.0 / (viewport[3] - viewport[1]), 1);
//}
SetColor(color);
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 (!legacy_mode)
// GL.PopMatrix();
}
// Clean layout
foreach (List<Vector2> list in active_lists.Values)
{
list.Clear();
inactive_lists.Enqueue(list);
}
active_lists.Clear();
GL.PopAttrib();
}
#endregion
#region Clear
public void Clear()
{
Cache.Clear();
}
#endregion
#region Begin
public void Begin()
{
if (disposed)
throw new ObjectDisposedException(this.GetType().ToString());
GraphicsContext.Assert();
int current_matrix;
GL.GetInteger(GetPName.MatrixMode, out current_matrix);
Viewport viewport = new Viewport();
GL.GetFloat(GetPName.Viewport, out viewport.Left);
// Prepare to draw text. We want pixel perfect precision, so we setup a 2D mode,
// with size equal to the window (in pixels).
// While we could also render text in 3D mode, it would be very hard to get
// pixel-perfect precision.
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.Ortho(viewport.Left, viewport.Right, viewport.Bottom, viewport.Top, -1.0, 1.0);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.MatrixMode((MatrixMode)current_matrix);
}
#endregion
#region End
public void End()
{
if (disposed)
throw new ObjectDisposedException(this.GetType().ToString());
GraphicsContext.Assert();
int current_matrix;
GL.GetInteger(GetPName.MatrixMode, out current_matrix);
GL.MatrixMode(MatrixMode.Modelview);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode((MatrixMode)current_matrix);
}
#endregion
#endregion
#region Protected Members
protected abstract void SetBlendFunction();
protected abstract void SetColor(Color color);
protected abstract TextQuality TextQuality { get; }
protected abstract GlyphCache Cache { get; }
#endregion
#region Static Members
public static GL1TextOutputProvider Create(TextQuality quality)
{
if (!GL.SupportsFunction("BlendFunc") || quality == TextQuality.Low || quality == TextQuality.Medium)
return new GL11TextOutputProvider(quality);
else
return new GL12TextOutputProvider(quality);
}
#endregion
#region IDisposable Members
public void Dispose()
{
if (!disposed)
{
Cache.Dispose();
disposed = true;
}
}
#endregion
}
}

View file

@ -0,0 +1,480 @@
#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
Dictionary<TextBlock, TextExtents> block_cache = new Dictionary<TextBlock, TextExtents>();
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<RectangleF> measured_glyphs = new List<RectangleF>(256);
readonly ObjectPool<PoolableTextExtents> text_extents_pool = new ObjectPool<PoolableTextExtents>();
// 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(TextBlock block)
{
return MeasureText(block, TextQuality.Default);
}
public TextExtents MeasureText(TextBlock block, TextQuality quality)
{
// First, check if we have cached this text block. Do not use block_cache.TryGetValue, to avoid thrashing
// the user's TextBlockExtents struct.
if (block_cache.ContainsKey(block))
return block_cache[block];
// If this block is not cached, we have to measure it and (potentially) place it in the cache.
TextExtents extents = MeasureTextExtents(block, quality);
if ((block.Options & TextPrinterOptions.NoCache) == 0)
block_cache.Add(block, 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(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;
}
}
extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, max_width, max_height);
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<RectangleF> 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;
}
}
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
}
}

View file

@ -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<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 bool IsWhiteSpace
public bool IsWhiteSpace
{
get { return Char.IsWhiteSpace(Character); }
}
#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
}
}

View file

@ -0,0 +1,155 @@
#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<T> : GlyphCache where T : Texture2D
{
#region Fields
List<GlyphSheet<T>> sheets = new List<GlyphSheet<T>>();
Bitmap bmp = new Bitmap(32, 32);
Dictionary<Glyph, CachedGlyphInfo> cached_glyphs = new Dictionary<Glyph, CachedGlyphInfo>();
bool disposed;
const int SheetWidth = 512, SheetHeight = 512;
#endregion
#region Constructors
public GlyphCache()
{
sheets.Add(new GlyphSheet<T>(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<T> sheet in sheets)
{
inserted = InsertGlyph(glyph, bmp, rect, sheet);
if (inserted)
break;
}
if (!inserted)
{
GlyphSheet<T> sheet = new GlyphSheet<T>(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<T> 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
}
}

View file

@ -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<Glyph>
{
#region Fields
string text;
Font font;
IEnumerator<char> 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<Glyph> 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
}
}

View file

@ -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)
/// <summary>
/// Adds boundingBox to the GlyphPacker.
/// </summary>
/// <param name="boundingBox">The bounding box of the item to pack.</param>
/// <param name="packedRectangle">The System.Drawing.Rectangle that contains the position of the packed item.</param>
/// <returns>True, if the item was successfully packed; false if the item is too big for this packer..</returns>
/// <exception cref="InvalidOperationException">Occurs if the item is larger than the available TexturePacker area</exception>
/// <exception cref="TexturePackerFullException">Occurs if the item cannot fit in the remaining packer space.</exception>
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)
/// <summary>
/// Adds boundingBox to the GlyphPacker.
/// </summary>
/// <param name="boundingBox">The bounding box of the item to pack.</param>
/// <param name="packedRectangle">The System.Drawing.RectangleF that contains the position of the packed item.</param>
/// <returns>True, if the item was successfully packed; false if the item is too big for this packer..</returns>
/// <exception cref="InvalidOperationException">Occurs if the item is larger than the available TexturePacker area</exception>
/// <exception cref="TexturePackerFullException">Occurs if the item cannot fit in the remaining packer space.</exception>
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)
/// <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="TexturePackerFullException">Occurs if the item cannot fit in the remaining packer space.</exception>
public Rectangle Add(Rectangle boundingBox)
{
if (!TryAdd(boundingBox, out boundingBox))
throw new TexturePackerFullException();
return boundingBox;
}
#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
#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.") { }
}
}

View file

@ -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<T> : 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
}
}

View file

@ -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();
}
}

View file

@ -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(TextBlock block);
TextExtents MeasureText(TextBlock block, TextQuality quality);
void Clear();
}
}

View file

@ -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(TextBlock block, Color color, IGlyphRasterizer rasterizer);
void Clear();
void Begin();
void End();
}
}

View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK.Graphics.Text
{
class PoolableTextExtents : TextExtents, IPoolable<PoolableTextExtents>
{
ObjectPool<PoolableTextExtents> owner;
#region Constructors
public PoolableTextExtents()
{
}
#endregion
#region IPoolable<PoolableTextExtents> Members
ObjectPool<PoolableTextExtents> IPoolable<PoolableTextExtents>.Owner
{
get { return owner; }
set { owner = value; }
}
#endregion
#region IPoolable Members
void IPoolable.OnAcquire()
{
Clear();
}
void IPoolable.OnRelease()
{
}
#endregion
}
}

View file

@ -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<TextBlock>, IEnumerable<Glyph>
{
#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<TextBlock> Members
public bool Equals(TextBlock other)
{
return
Text == other.Text &&
Font == other.Font &&
Bounds == other.Bounds &&
Options == other.Options;
}
#endregion
#region IEnumerable<Glyph> Members
public IEnumerator<Glyph> GetEnumerator()
{
return new GlyphEnumerator(Text, Font);
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return new GlyphEnumerator(Text, Font);
}
#endregion
}
}

View file

@ -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<TextBlock>
{
#region Constructors
public TextBlockComparer() { }
#endregion
#region IComparer<TextBlock> Members
public int Compare(TextBlock x, TextBlock y)
{
return x.UsageCount.CompareTo(y.UsageCount);
}
#endregion
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK.Graphics
{
/// <summary>
/// Defines available alignments for text.
/// </summary>
public enum TextAlignment
{
/// <summary>The text is aligned to the near side (left for left-to-right text and right for right-to-left text).</summary>
Near = 0,
/// <summary>The text is aligned to the center.</summary>
Center,
/// <summary>The text is aligned to the far side (right for left-to-right text and left for right-to-left text).</summary>
Far
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK.Graphics
{
/// <summary>
/// Defines available directions for text layout.
/// </summary>
public enum TextDirection
{
/// <summary>The text is layed out from left to right.</summary>
LeftToRight,
/// <summary>The text is layed out from right to left.</summary>
RightToLeft,
/// <summary>The text is layed out vertically.</summary>
Vertical
}
}

View file

@ -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
{
/// <summary>
/// Holds the results of a text measurement.
/// </summary>
public class TextExtents : IDisposable
{
#region Fields
protected RectangleF text_extents;
protected List<RectangleF> glyph_extents = new List<RectangleF>();
public static readonly TextExtents Empty = new TextExtents();
#endregion
#region Constructors
internal TextExtents()
{
}
#endregion
#region Public Members
/// <summary>
/// Gets the bounding box of the measured text.
/// </summary>
public RectangleF BoundingBox
{
get { return text_extents; }
internal set { text_extents = value; }
}
/// <summary>
/// Gets the extents of each glyph in the measured text.
/// </summary>
/// <param name="i">The index of the glyph.</param>
/// <returns>The extents of the specified glyph.</returns>
public RectangleF this[int i]
{
get { return glyph_extents[i]; }
internal set { glyph_extents[i] = value; }
}
/// <summary>
/// Gets the extents of each glyph in the measured text.
/// </summary>
public IEnumerable<RectangleF> GlyphExtents
{
get { return (IEnumerable<RectangleF>)glyph_extents; }
}
/// <summary>
/// Gets the number of the measured glyphs.
/// </summary>
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<RectangleF> 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
/// <summary>
/// Frees the resources consumed by this TextExtents instance.
/// </summary>
public virtual void Dispose()
{
}
#endregion
}
}

View file

@ -0,0 +1,337 @@
#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.Math;
using OpenTK.Graphics;
using OpenTK.Graphics.Text;
using OpenTK.Platform;
namespace OpenTK.Fonts { }
namespace OpenTK.Graphics
{
/// <summary>
/// Provides methods to perform layout and print hardware accelerated text.
/// </summary>
public sealed class TextPrinter : ITextPrinter
{
#region Fields
IGlyphRasterizer glyph_rasterizer;
ITextOutputProvider text_output;
TextQuality text_quality;
bool disposed;
#endregion
#region Constructors
/// <summary>
/// Constructs a new TextPrinter instance.
/// </summary>
public TextPrinter()
: this(null, null, TextQuality.Default) { }
/// <summary>
/// Constructs a new TextPrinter instance with the specified TextQuality level.
/// </summary>
/// <param name="quality">The desired TextQuality of this TextPrinter.</param>
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
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
public void Print(string text, Font font, Color color)
{
Print(text, font, color, RectangleF.Empty, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight);
}
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
public void Print(string text, Font font, Color color, RectangleF rect)
{
Print(text, font, color, rect, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight);
}
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to print text.</param>
public void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options)
{
Print(text, font, color, rect, options, TextAlignment.Near, TextDirection.LeftToRight);
}
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to print text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to print text.</param>
public void Print(string text, Font font, Color color, RectangleF rect, TextPrinterOptions options, TextAlignment alignment)
{
Print(text, font, color, rect, options, alignment, TextDirection.LeftToRight);
}
/// <summary>
/// Prints text using the specified color and layout options.
/// </summary>
/// <param name="text">The System.String to print.</param>
/// <param name="font">The System.Drawing.Font that will be used to print text.</param>
/// <param name="color">The System.Drawing.Color that will be used to print text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to print text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to print text.</param>
/// <param name="direction">The OpenTK.Graphics.TextDirection that will be used to print text.</param>
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;
TextOutput.Print(new TextBlock(text, font, rect, options, alignment, direction), color, Rasterizer);
}
#endregion
#region Measure
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
public TextExtents Measure(string text, Font font)
{
return Measure(text, font, RectangleF.Empty, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight);
}
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
public TextExtents Measure(string text, Font font, RectangleF rect)
{
return Measure(text, font, rect, TextPrinterOptions.Default, TextAlignment.Near, TextDirection.LeftToRight);
}
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to measure text.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
public TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options)
{
return Measure(text, font, rect, options, TextAlignment.Near, TextDirection.LeftToRight);
}
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to measure text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to measure text.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
public TextExtents Measure(string text, Font font, RectangleF rect, TextPrinterOptions options, TextAlignment alignment)
{
return Measure(text, font, rect, options, alignment, TextDirection.LeftToRight);
}
/// <summary>
/// Measures text using the specified layout options.
/// </summary>
/// <param name="text">The System.String to measure.</param>
/// <param name="font">The System.Drawing.Font that will be used to measure text.</param>
/// <param name="rect">The System.Drawing.Rectangle that defines the bounds for text layout.</param>
/// <param name="options">The OpenTK.Graphics.TextPrinterOptions that will be used to measure text.</param>
/// <param name="alignment">The OpenTK.Graphics.TextAlignment that will be used to measure text.</param>
/// <param name="direction">The OpenTK.Graphics.TextDirection that will be used to measure text.</param>
/// <returns>An OpenTK.Graphics.TextExtents instance that contains the results of the measurement.</returns>
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;
return Rasterizer.MeasureText(new TextBlock(text, font, rect, options, alignment, direction));
}
#endregion
#region Clear
public void Clear()
{
if (disposed)
throw new ObjectDisposedException(this.GetType().ToString());
TextOutput.Clear();
Rasterizer.Clear();
}
#endregion
#region Begin
/// <summary>
/// Sets up a resolution-dependent orthographic projection.
/// </summary>
public void Begin()
{
TextOutput.Begin();
}
#endregion
#region Begin
/// <summary>
/// Restores the projection and modelview matrices to their previous state.
/// </summary>
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("size");
return true;
}
#endregion
#region IDisposable Members
/// <summary>
/// Frees the resources consumed by this TextPrinter object.
/// </summary>
public void Dispose()
{
if (!disposed)
{
TextOutput.Dispose();
disposed = true;
}
}
#endregion
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK.Graphics
{
/// <summary>
/// Defines available options for the TextPrinter.
/// </summary>
[Flags]
public enum TextPrinterOptions
{
/// <summary>The TextPrinter will use default printing options.</summary>
Default = 0x0000,
/// <summary>The TextPrinter will not cache text blocks as they are measured or printed.</summary>
NoCache = 0x0001,
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK.Graphics
{
/// <summary>
/// Defines available quality levels for text printing.
/// </summary>
public enum TextQuality
{
/// <summary>Use the default quality, as specified by the operating system.</summary>
Default = 0,
/// <summary>Use fast, low quality text (typically non-antialiased) .</summary>
Low,
/// <summary>Use medium quality text (typically grayscale antialiased).</summary>
Medium,
/// <summary>Use slow, high quality text (typically subpixel antialiased).</summary>
High
}
}

View file

@ -0,0 +1,317 @@
#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace OpenTK.Graphics
{
abstract class Texture2D : IGraphicsResource, IEquatable<Texture2D>
{
#region Fields
GraphicsContext context;
int id;
int width, height;
bool disposed;
TextureMagFilter mag_filter = TextureMagFilter.Linear;
TextureMinFilter min_filter = TextureMinFilter.Linear;
#endregion
#region Constructors
public Texture2D(int width, int height)
{
if (width <= 0)
throw new ArgumentOutOfRangeException("width");
if (height <= 0)
throw new ArgumentOutOfRangeException("height");
Width = width;
Height = height;
}
#endregion
#region Public Members
#region public int Width
/// <summary>Gets the width of the texture.</summary>
public int Width { get { return width; } private set { width = value; } }
#endregion
#region public int Height
/// <summary>Gets the height of the texture.</summary>
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<int> region = new TextureRegion2D<int>(rect);
GL.GetTexImage(TextureTarget.Texture2D, mipLevel, 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
GraphicsContext 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<Texture2D> 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);
}
disposed = true;
}
}
~Texture2D()
{
GraphicsContext context = (this as IGraphicsResource).Context;
if (context != null)
(context as IGraphicsContextInternal).RegisterForDisposal(this);
}
#endregion
}
}

View file

@ -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; } }
}
/// <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
}
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK
{
interface IPoolable : IDisposable
{
void OnAcquire();
void OnRelease();
}
interface IPoolable<T> : IPoolable where T : IPoolable<T>, new()
{
ObjectPool<T> Owner { get; set; }
}
}

View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK
{
class ObjectPool<T> where T : IPoolable<T>, new()
{
Queue<T> pool = new Queue<T>();
public ObjectPool()
{ }
public T Acquire()
{
T item;
if (pool.Count > 0)
{
item = pool.Dequeue();
item.OnAcquire();
}
else
{
item = new T();
item.Owner = this;
item.OnAcquire();
}
return item;
}
public void Release(T item)
{
if (item == null)
throw new ArgumentNullException("item");
item.OnRelease();
pool.Enqueue(item);
}
}
}

View file

@ -54,7 +54,7 @@ namespace OpenTK
// Tree is full and insertion failed:
if (node == null)
throw new InvalidOperationException("There is not enough space to add this item. Consider calling the Clear() method.");
throw new TexturePackerFullException();
//items.Add(item, node);
rect = node.Rect;
@ -193,4 +193,9 @@ namespace OpenTK
#endregion
}
class TexturePackerFullException : Exception
{
public TexturePackerFullException() : base("There is not enough space to add this item. Consider calling the Clear() method.") { }
}
}