2007-11-02 00:17:57 +01:00
#region - - - License - - -
/ * Copyright ( c ) 2006 , 2007 Stefanos Apostolopoulos
* See license . txt for license info
* /
#endregion
using System ;
2007-10-20 12:31:59 +02:00
using System.Collections.Generic ;
using System.Text ;
using System.Drawing.Text ;
2008-01-23 13:42:07 +01:00
using System.Drawing ;
using System.Drawing.Imaging ;
using System.Runtime.InteropServices ;
using System.Diagnostics ;
2007-10-20 12:31:59 +02:00
using OpenTK.Math ;
2008-04-13 18:45:56 +02:00
using OpenTK.Graphics ;
2007-10-20 12:31:59 +02:00
using OpenTK.Platform ;
2008-03-08 15:38:10 +01:00
namespace OpenTK.Graphics
2007-10-20 12:31:59 +02:00
{
2008-01-23 13:42:07 +01:00
using Graphics = System . Drawing . Graphics ;
2008-04-13 18:45:56 +02:00
using PixelFormat = OpenTK . Graphics . PixelFormat ;
2008-01-23 13:42:07 +01:00
2007-11-02 00:17:57 +01:00
public class TextureFont : IFont
2007-10-20 12:31:59 +02:00
{
2007-11-06 21:59:15 +01:00
Font font ;
2008-06-22 18:29:13 +02:00
Dictionary < char , RectangleF > loaded_glyphs = new Dictionary < char , RectangleF > ( 64 ) ;
2007-11-02 00:17:57 +01:00
2007-11-06 21:59:15 +01:00
Bitmap bmp ;
Graphics gfx ;
2007-11-08 16:54:38 +01:00
// TODO: We need to be able to use multiple font sheets.
2007-10-20 12:31:59 +02:00
static int texture ;
static TexturePacker < Glyph > pack ;
static int texture_width , texture_height ;
2008-06-29 12:56:51 +02:00
static StringFormat default_string_format = StringFormat . GenericTypographic ;
2008-06-24 20:27:51 +02:00
static SizeF maximum_graphics_size ;
int [ ] data = new int [ 256 ] ; // Used to upload the glyph buffer to the OpenGL texture.
2007-11-08 16:54:38 +01:00
object upload_lock = new object ( ) ;
2007-10-20 12:31:59 +02:00
2007-11-02 00:17:57 +01:00
#region - - - Constructor - - -
2007-10-26 17:55:24 +02:00
/// <summary>
2008-06-24 20:27:51 +02:00
/// Constructs a new TextureFont, using the specified System.Drawing.Font.
2007-10-26 17:55:24 +02:00
/// </summary>
2007-11-02 00:17:57 +01:00
/// <param name="font">The System.Drawing.Font to use.</param>
2007-11-08 16:54:38 +01:00
public TextureFont ( Font font )
2007-10-20 12:31:59 +02:00
{
if ( font = = null )
throw new ArgumentNullException ( "font" , "Argument to TextureFont constructor cannot be null." ) ;
this . font = font ;
2007-11-06 21:59:15 +01:00
bmp = new Bitmap ( font . Height * 2 , font . Height * 2 ) ;
gfx = Graphics . FromImage ( bmp ) ;
2008-06-24 20:27:51 +02:00
maximum_graphics_size = gfx . ClipBounds . Size ;
2007-11-08 16:54:38 +01:00
// Adjust font rendering mode. Small sizes look blurry without gridfitting, so turn
// that on. Increasing contrast also seems to help.
if ( font . Size < = 18.0f )
{
gfx . TextRenderingHint = TextRenderingHint . AntiAliasGridFit ;
2008-06-29 12:56:51 +02:00
//gfx.TextContrast = 11;
2007-11-08 16:54:38 +01:00
}
else
{
gfx . TextRenderingHint = TextRenderingHint . AntiAlias ;
2008-06-29 12:56:51 +02:00
//gfx.TextContrast = 0;
2007-11-08 16:54:38 +01:00
}
2007-10-20 12:31:59 +02:00
}
2008-06-24 20:27:51 +02:00
/// <summary>
/// Constructs a new TextureFont, using the specified parameters.
/// </summary>
/// <param name="font">The System.Drawing.FontFamily to use for the typeface.</param>
/// <param name="emSize">The em size to use for the typeface.</param>
public TextureFont ( FontFamily family , float emSize )
: this ( new Font ( family , emSize ) )
{ }
/// <summary>
/// Constructs a new TextureFont, using the specified parameters.
/// </summary>
/// <param name="font">The System.Drawing.FontFamily to use for the typeface.</param>
/// <param name="emSize">The em size to use for the typeface.</param>
/// <param name="family">The style to use for the typeface.</param>
public TextureFont ( FontFamily family , float emSize , FontStyle style )
: this ( new Font ( family , emSize , style ) )
{ }
2007-11-02 00:17:57 +01:00
#endregion
2008-06-22 01:23:33 +02:00
#region - - - Public Methods - - -
2007-11-02 00:17:57 +01:00
#region public void LoadGlyphs ( string glyphs )
2007-10-20 12:31:59 +02:00
/// <summary>
2007-10-26 17:55:24 +02:00
/// Prepares the specified glyphs for rendering.
2007-10-20 12:31:59 +02:00
/// </summary>
2007-10-26 17:55:24 +02:00
/// <param name="glyphs">The glyphs to prepare for rendering.</param>
2007-10-20 12:31:59 +02:00
public void LoadGlyphs ( string glyphs )
{
2008-06-22 18:29:13 +02:00
RectangleF rect = new RectangleF ( ) ;
2007-10-20 12:31:59 +02:00
foreach ( char c in glyphs )
{
2008-06-24 20:27:51 +02:00
try
{
if ( ! loaded_glyphs . ContainsKey ( c ) )
LoadGlyph ( c , out rect ) ;
}
catch ( Exception e )
{
Debug . Print ( e . ToString ( ) ) ;
throw ;
}
2007-10-20 12:31:59 +02:00
}
}
2007-11-02 00:17:57 +01:00
#endregion
2007-11-06 21:59:15 +01:00
#region public void LoadGlyph ( char glyph )
/// <summary>
/// Prepares the specified glyph for rendering.
/// </summary>
/// <param name="glyphs">The glyph to prepare for rendering.</param>
public void LoadGlyph ( char glyph )
{
2008-06-22 18:29:13 +02:00
RectangleF rect = new RectangleF ( ) ;
2007-11-06 21:59:15 +01:00
if ( ! loaded_glyphs . ContainsKey ( glyph ) )
LoadGlyph ( glyph , out rect ) ;
}
#endregion
2008-06-22 18:29:13 +02:00
#region public bool GlyphData ( char glyph , out float width , out float height , out RectangleF textureRectangle , out int texture )
2007-11-02 00:17:57 +01:00
2007-11-06 14:30:46 +01:00
/// <summary>
/// Returns the characteristics of a loaded glyph.
/// </summary>
/// <param name="glyph">The character corresponding to this glyph.</param>
/// <param name="width">The width of this glyph.</param>
/// <param name="height">The height of this glyph (line spacing).</param>
2008-04-04 21:46:08 +02:00
/// <param name="textureRectangle">The bounding box of the texture buffer of this glyph.</param>
2007-11-06 14:30:46 +01:00
/// <param name="texture">The handle to the texture that contains this glyph.</param>
/// <returns>True if the glyph has been loaded, false otherwise.</returns>
/// <seealso cref="LoadGlyphs"/>
2008-06-22 18:29:13 +02:00
public bool GlyphData ( char glyph , out float width , out float height , out RectangleF textureRectangle , out int texture )
2007-11-02 00:17:57 +01:00
{
if ( loaded_glyphs . TryGetValue ( glyph , out textureRectangle ) )
{
width = textureRectangle . Width * texture_width ;
height = textureRectangle . Height * texture_height ;
texture = TextureFont . texture ;
return true ;
}
width = height = texture = 0 ;
return false ;
}
#endregion
2007-11-06 14:30:46 +01:00
#region public float Height
2007-11-02 00:17:57 +01:00
2007-10-26 17:55:24 +02:00
/// <summary>
2007-11-06 14:30:46 +01:00
/// Gets a float indicating the default line spacing of this font.
2007-10-26 17:55:24 +02:00
/// </summary>
2007-11-06 14:30:46 +01:00
public float Height
2007-10-26 17:55:24 +02:00
{
2007-11-06 14:30:46 +01:00
get { return font . Height ; }
2007-10-20 12:31:59 +02:00
}
2007-11-02 00:17:57 +01:00
#endregion
2007-11-06 21:59:15 +01:00
#region public float Width
/// <summary>
2008-06-24 22:35:37 +02:00
/// Gets a float indicating the default size of this font, in points.
2007-11-06 21:59:15 +01:00
/// </summary>
public float Width
{
get { return font . SizeInPoints ; }
}
#endregion
2008-02-02 13:29:21 +01:00
#region public void MeasureString ( string str , out float width , out float height , bool accountForOverhangs )
/// <summary>
/// Measures the width of the specified string.
/// </summary>
/// <param name="str">The string to measure.</param>
/// <param name="width">The measured width.</param>
/// <param name="height">The measured height.</param>
2008-06-22 18:29:13 +02:00
/// <param name="accountForOverhangs">If true, adds space to account for glyph overhangs. Set to true if you wish to measure a complete string. Set to false if you wish to perform layout on adjacent strings.</param>
2008-06-24 20:27:51 +02:00
[Obsolete("Returns invalid results - use MeasureText() instead")]
2008-02-02 13:29:21 +01:00
public void MeasureString ( string str , out float width , out float height , bool accountForOverhangs )
{
System . Drawing . StringFormat format = accountForOverhangs ? System . Drawing . StringFormat . GenericDefault : System . Drawing . StringFormat . GenericTypographic ;
2008-06-22 18:29:13 +02:00
//format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
2008-02-02 13:29:21 +01:00
System . Drawing . SizeF size = gfx . MeasureString ( str , font , 16384 , format ) ;
height = size . Height ;
width = size . Width ;
2008-06-22 18:29:13 +02:00
//width = height = 0;
//RectangleF rect = new RectangleF(0, 0, 0, 0);
//ICollection<RectangleF> ranges = new List<RectangleF>();
//MeasureCharacterRanges(gfx, str, font, ref rect, format, ref ranges);
//foreach (RectangleF range in ranges)
//{
// width += range.Width;
// height = range.Height > height ?range.Height : height;
//}
2008-02-02 13:29:21 +01:00
// width = 0;
// height = 0;
// int i = 0;
// foreach (char c in str)
// {
// if (c != '\n' && c != '\r')
// {
// SizeF size = gfx.MeasureString(str.Substring(i, 1), font, 16384, System.Drawing.StringFormat.GenericTypographic);
// width += size.Width == 0 ? font.SizeInPoints * 0.5f : size.Width;
// if (height < size.Height)
// height = size.Height;
// }
// ++i;
// }
}
#endregion
2007-11-06 14:30:46 +01:00
#region public void MeasureString ( string str , out float width , out float height )
2007-11-02 00:17:57 +01:00
2007-10-26 17:55:24 +02:00
/// <summary>
/// Measures the width of the specified string.
/// </summary>
2007-11-06 14:30:46 +01:00
/// <param name="str">The string to measure.</param>
/// <param name="width">The measured width.</param>
/// <param name="height">The measured height.</param>
2008-02-02 13:29:21 +01:00
/// <seealso cref="public void MeasureString(string str, out float width, out float height, bool accountForOverhangs)"/>
2008-06-24 20:27:51 +02:00
[Obsolete("Returns invalid results - use MeasureText() instead")]
2007-11-06 14:30:46 +01:00
public void MeasureString ( string str , out float width , out float height )
2007-10-26 17:55:24 +02:00
{
2008-02-02 13:29:21 +01:00
MeasureString ( str , out width , out height , true ) ;
2007-10-26 17:55:24 +02:00
}
2007-10-20 12:31:59 +02:00
2007-11-02 00:17:57 +01:00
#endregion
2008-06-24 20:27:51 +02:00
#region public RectangleF MeasureText ( string text )
2008-06-22 18:29:13 +02:00
/// <summary>
2008-06-24 20:27:51 +02:00
/// Calculates size information for the specified text.
2008-06-22 18:29:13 +02:00
/// </summary>
/// <param name="text">The string to measure.</param>
2008-06-24 20:27:51 +02:00
/// <returns>A RectangleF containing the bounding box for the specified text.</returns>
public RectangleF MeasureText ( string text )
2008-06-22 18:29:13 +02:00
{
2008-06-24 20:27:51 +02:00
return MeasureText ( text , SizeF . Empty , default_string_format , null ) ;
2008-06-22 18:29:13 +02:00
}
#endregion
2008-06-24 20:27:51 +02:00
#region public RectangleF MeasureText ( string text , SizeF bounds )
2008-06-22 18:29:13 +02:00
/// <summary>
2008-06-24 20:27:51 +02:00
/// Calculates size information for the specified text.
2008-06-22 18:29:13 +02:00
/// </summary>
/// <param name="text">The string to measure.</param>
2008-06-24 20:27:51 +02:00
/// <param name="bounds">A SizeF structure containing the maximum desired width and height of the text. Default is SizeF.Empty.</param>
/// <returns>A RectangleF containing the bounding box for the specified text.</returns>
public RectangleF MeasureText ( string text , SizeF bounds )
2008-06-22 18:29:13 +02:00
{
2008-06-24 20:27:51 +02:00
return MeasureText ( text , bounds , default_string_format , null ) ;
2008-06-22 18:29:13 +02:00
}
#endregion
2008-06-24 20:27:51 +02:00
#region public RectangleF MeasureText ( string text , SizeF bounds , StringFormat format )
2008-06-22 01:23:33 +02:00
2008-06-24 20:27:51 +02:00
/// <summary>
/// Calculates size information for the specified text.
/// </summary>
/// <param name="text">The string to measure.</param>
/// <param name="bounds">A SizeF structure containing the maximum desired width and height of the text. Pass SizeF.Empty to disable wrapping calculations. A width or height of 0 disables the relevant calculation.</param>
2008-06-29 12:56:51 +02:00
/// <param name="format">A StringFormat object which specifies the measurement format of the string. Pass null to use the default StringFormat (StringFormat.GenericTypographic).</param>
2008-06-24 20:27:51 +02:00
/// <returns>A RectangleF containing the bounding box for the specified text.</returns>
public RectangleF MeasureText ( string text , SizeF bounds , StringFormat format )
{
return MeasureText ( text , bounds , format , null ) ;
}
2008-06-22 01:23:33 +02:00
2008-06-24 20:27:51 +02:00
#endregion
2008-06-22 18:29:13 +02:00
2008-06-24 20:27:51 +02:00
#region public RectangleF MeasureText ( string text , SizeF bounds , StringFormat format , IList < RectangleF > ranges )
2008-06-22 18:29:13 +02:00
2008-06-24 20:27:51 +02:00
/// <summary>
/// Calculates size information for the specified text.
/// </summary>
/// <param name="text">The string to measure.</param>
/// <param name="bounds">A SizeF structure containing the maximum desired width and height of the text. Pass SizeF.Empty to disable wrapping calculations. A width or height of 0 disables the relevant calculation.</param>
2008-06-28 19:44:24 +02:00
/// <param name="format">A StringFormat object which specifies the measurement format of the string. Pass null to use the default StringFormat (StringFormat.GenericDefault).</param>
2008-06-24 20:27:51 +02:00
/// <param name="ranges">Fills the specified IList of RectangleF structures with position information for individual characters. If this argument is null, these calculations are skipped.</param>
/// <returns>A RectangleF containing the bounding box for the specified text.</returns>
public RectangleF MeasureText ( string text , SizeF bounds , StringFormat format , IList < RectangleF > ranges )
{
2008-06-22 18:29:13 +02:00
int status = 0 ;
2008-06-24 20:27:51 +02:00
RectangleF bounding_box = new RectangleF ( ) ;
2008-06-22 18:29:13 +02:00
if ( String . IsNullOrEmpty ( text ) )
2008-06-24 20:27:51 +02:00
return RectangleF . Empty ;
if ( bounds = = SizeF . Empty )
bounds = maximum_graphics_size ;
2008-06-22 18:29:13 +02:00
2008-06-24 20:27:51 +02:00
if ( format = = null )
format = default_string_format ;
2008-06-22 18:29:13 +02:00
2008-06-24 22:35:37 +02:00
if ( ranges ! = null )
ranges . Clear ( ) ;
2008-06-22 18:29:13 +02:00
IntPtr [ ] regions = new IntPtr [ GdiPlus . MaxMeasurableCharacterRanges ] ;
CharacterRange [ ] characterRanges = new CharacterRange [ GdiPlus . MaxMeasurableCharacterRanges ] ;
2008-06-24 22:35:37 +02:00
PointF origin = PointF . Empty ;
SizeF size = SizeF . Empty ;
RectangleF rect = new RectangleF ( ) ;
2008-06-22 18:29:13 +02:00
for ( int i = 0 ; i < text . Length ; i + = GdiPlus . MaxMeasurableCharacterRanges )
{
int num_characters = text . Length - i > GdiPlus . MaxMeasurableCharacterRanges ? GdiPlus . MaxMeasurableCharacterRanges : text . Length - i ;
for ( int j = 0 ; j < num_characters ; j + + )
{
characterRanges [ j ] = new CharacterRange ( i + j , 1 ) ;
IntPtr region ;
status = GdiPlus . CreateRegion ( out region ) ;
regions [ j ] = region ;
if ( status ! = 0 )
Debug . Print ( "GDI+ error: {0}" , status ) ;
}
CharacterRange [ ] a = ( CharacterRange [ ] ) characterRanges . Clone ( ) ;
Array . Resize ( ref a , num_characters ) ;
format . SetMeasurableCharacterRanges ( a ) ;
IntPtr native_graphics = GdiPlus . GetNativeGraphics ( gfx ) ;
IntPtr native_font = GdiPlus . GetNativeFont ( font ) ;
IntPtr native_string_format = GdiPlus . GetNativeStringFormat ( format ) ;
2008-06-24 20:27:51 +02:00
RectangleF layoutRect = new RectangleF ( PointF . Empty , bounds ) ;
2008-06-22 18:29:13 +02:00
status = GdiPlus . MeasureCharacterRanges ( new HandleRef ( gfx , native_graphics ) , text , text . Length ,
new HandleRef ( font , native_font ) , ref layoutRect ,
new HandleRef ( format , ( format = = null ) ? IntPtr . Zero : native_string_format ) ,
num_characters , regions ) ;
for ( int j = 0 ; j < num_characters ; j + + )
{
2008-06-24 22:35:37 +02:00
status = GdiPlus . GetRegionBounds ( regions [ j ] , new HandleRef ( gfx , GdiPlus . GetNativeGraphics ( gfx ) ) , ref rect ) ;
if ( i = = 0 & & j = = 0 )
origin = rect . Location ;
2008-06-22 18:29:13 +02:00
2008-06-29 12:56:51 +02:00
//if (origin.X > 0)
// rect.X -= (float)System.Math.Floor(origin.X);
2008-06-24 20:27:51 +02:00
if ( ranges ! = null )
2008-06-24 22:35:37 +02:00
ranges . Add ( rect ) ;
2008-06-22 18:29:13 +02:00
status = GdiPlus . DeleteRegion ( regions [ j ] ) ;
}
}
2008-06-24 22:35:37 +02:00
2008-06-29 12:56:51 +02:00
//origin.X = 0;
return new RectangleF ( origin . X , origin . Y , rect . Right , rect . Bottom ) ;
2008-06-22 18:29:13 +02:00
}
#endregion
2008-06-29 12:56:51 +02:00
#endregion
#region - - - Private Methods - - -
2008-06-22 01:23:33 +02:00
#region private void PrepareTexturePacker ( )
/// <summary>
/// Calculates the optimal size for the font texture and TexturePacker, and creates both.
/// </summary>
private void PrepareTexturePacker ( )
{
// Calculate the size of the texture packer. We want a power-of-two size
// that is less than 1024 (supported in Geforce256-era cards), but large
// enough to hold at least 256 (16*16) font glyphs.
// TODO: Find the actual card limits, maybe?
int size = ( int ) ( font . Size * 16 ) ;
size = ( int ) System . Math . Pow ( 2.0 , System . Math . Ceiling ( System . Math . Log ( ( double ) size , 2.0 ) ) ) ;
if ( size > 1024 )
size = 1024 ;
texture_width = size ;
texture_height = size ;
pack = new TexturePacker < Glyph > ( texture_width , texture_height ) ;
GL . GenTextures ( 1 , out texture ) ;
GL . BindTexture ( TextureTarget . Texture2D , texture ) ;
GL . TexParameter ( TextureTarget . Texture2D , TextureParameterName . TextureMinFilter , ( int ) All . Linear ) ;
GL . TexParameter ( TextureTarget . Texture2D , TextureParameterName . TextureMagFilter , ( int ) All . Linear ) ;
GL . TexImage2D ( TextureTarget . Texture2D , 0 , PixelInternalFormat . Alpha , texture_width , texture_height , 0 ,
OpenTK . Graphics . PixelFormat . Rgba , PixelType . UnsignedByte , IntPtr . Zero ) ;
}
#endregion
2008-06-24 22:35:37 +02:00
#region private void LoadGlyph ( char c , out RectangleF rectangle )
2008-06-22 01:23:33 +02:00
2008-06-24 22:35:37 +02:00
// Adds the specified caharacter to the texture packer.
2008-06-22 18:29:13 +02:00
private void LoadGlyph ( char c , out RectangleF rectangle )
2008-06-22 01:23:33 +02:00
{
if ( pack = = null )
PrepareTexturePacker ( ) ;
2008-06-29 12:56:51 +02:00
RectangleF glyph_rect = MeasureText ( c . ToString ( ) , SizeF . Empty , default_string_format ) ;
2008-06-24 22:35:37 +02:00
SizeF glyph_size = new SizeF ( glyph_rect . Right , glyph_rect . Bottom ) ; // We need to do this, since the origin might not be (0, 0)
Glyph g = new Glyph ( c , font , glyph_size ) ;
Rectangle rect ;
2008-06-22 01:23:33 +02:00
try
{
pack . Add ( g , out rect ) ;
}
catch ( InvalidOperationException expt )
{
// TODO: The TexturePacker is full, create a new font sheet.
Trace . WriteLine ( expt ) ;
throw ;
}
GL . BindTexture ( TextureTarget . Texture2D , texture ) ;
2008-06-24 22:35:37 +02:00
//gfx.TextRenderingHint = TextRenderingHint.AntiAlias;
2008-06-22 01:23:33 +02:00
gfx . Clear ( System . Drawing . Color . Transparent ) ;
2008-06-29 12:56:51 +02:00
gfx . DrawString ( g . Character . ToString ( ) , g . Font , System . Drawing . Brushes . White , 0.0f , 0.0f , default_string_format ) ;
2008-06-22 01:23:33 +02:00
//BitmapData bitmap_data = bitmap.LockBits(new Rectangle(0, 0, rect.Width, rect.Height), ImageLockMode.ReadOnly,
// System.Drawing.Imaging.PixelFormat.Format32bppArgb);
//GL.TexSubImage2D(TextureTarget.Texture2D, 0, rect.Left, rect.Top, rect.Width, rect.Height,
// OpenTK.Graphics.Enums.PixelFormat.Rgba, PixelType.UnsignedByte, bitmap_data.Scan0);
//bitmap.UnlockBits(bitmap_data);
BitmapData bitmap_data = bmp . LockBits ( new Rectangle ( 0 , 0 , bmp . Width , bmp . Height ) , ImageLockMode . ReadOnly ,
System . Drawing . Imaging . PixelFormat . Format32bppArgb ) ;
int needed_size = rect . Width * rect . Height ;
if ( data . Length < needed_size )
Array . Resize < int > ( ref data , needed_size ) ;
Array . Clear ( data , 0 , needed_size ) ;
unsafe
{
int * bitmap_data_ptr = ( int * ) bitmap_data . Scan0 ;
for ( int y = 0 ; y < rect . Height ; y + + )
for ( int x = 0 ; x < rect . Width ; x + + )
data [ y * rect . Width + x ] = * ( bitmap_data_ptr + y * bmp . Width + x ) ;
fixed ( int * data_ptr = data )
GL . TexSubImage2D ( TextureTarget . Texture2D , 0 , rect . Left , rect . Top , rect . Width , rect . Height ,
OpenTK . Graphics . PixelFormat . Rgba , PixelType . UnsignedByte , ( IntPtr ) data_ptr ) ;
}
bmp . UnlockBits ( bitmap_data ) ;
2008-06-22 18:29:13 +02:00
rectangle = RectangleF . FromLTRB (
2008-06-22 01:23:33 +02:00
rect . Left / ( float ) texture_width ,
rect . Top / ( float ) texture_height ,
rect . Right / ( float ) texture_width ,
rect . Bottom / ( float ) texture_height ) ;
loaded_glyphs . Add ( g . Character , rectangle ) ;
}
#endregion
#endregion
#region - - - Internal Methods - - -
#region internal int Texture
/// <summary>
/// Gets the handle to the texture were this font resides.
/// </summary>
internal int Texture
{
get { return TextureFont . texture ; }
}
#endregion
#endregion
2007-11-02 00:17:57 +01:00
#region - - - IDisposable Members - - -
2007-10-20 12:31:59 +02:00
2007-10-26 17:55:24 +02:00
bool disposed ;
2007-10-20 12:31:59 +02:00
2007-10-26 17:55:24 +02:00
/// <summary>
2008-03-08 15:38:10 +01:00
/// Releases all resources used by this OpenTK.Graphics.TextureFont.
2007-10-26 17:55:24 +02:00
/// </summary>
public void Dispose ( )
{
GC . SuppressFinalize ( this ) ;
Dispose ( true ) ;
2007-10-20 12:31:59 +02:00
}
2007-10-26 17:55:24 +02:00
private void Dispose ( bool manual )
2007-10-20 12:31:59 +02:00
{
2007-10-26 17:55:24 +02:00
if ( ! disposed )
{
pack = null ;
if ( manual )
{
GL . DeleteTextures ( 1 , ref texture ) ;
font . Dispose ( ) ;
gfx . Dispose ( ) ;
}
disposed = true ;
}
2007-10-20 12:31:59 +02:00
}
2007-10-26 17:55:24 +02:00
~ TextureFont ( )
2007-10-20 12:31:59 +02:00
{
2007-10-26 17:55:24 +02:00
Dispose ( false ) ;
2007-10-20 12:31:59 +02:00
}
2007-10-26 17:55:24 +02:00
#endregion
2007-10-20 12:31:59 +02:00
}
}