mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-25 07:45:35 +00:00
Fixed TextExtents behavior when returning either cached or uncached instances.
Reduced memory pressure by adding object pooling to TextExtents.
This commit is contained in:
parent
a868c4b4e8
commit
c0549b11fa
|
@ -57,63 +57,64 @@ namespace OpenTK.Graphics.Text
|
||||||
|
|
||||||
public void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache)
|
public void Print(TextBlock block, IGlyphRasterizer rasterizer, GlyphCache cache)
|
||||||
{
|
{
|
||||||
TextExtents extents = rasterizer.MeasureText(block);
|
using (TextExtents extents = rasterizer.MeasureText(block))
|
||||||
|
|
||||||
//GL.BindTexture(TextureTarget.Texture2D, 2);
|
|
||||||
|
|
||||||
//GL.Begin(BeginMode.Quads);
|
|
||||||
|
|
||||||
//GL.TexCoord2(0, 0);
|
|
||||||
//GL.Vertex2(0, 0);
|
|
||||||
//GL.TexCoord2(1, 0);
|
|
||||||
//GL.Vertex2(256, 0);
|
|
||||||
//GL.TexCoord2(1, 1);
|
|
||||||
//GL.Vertex2(256, 256);
|
|
||||||
//GL.TexCoord2(0, 1);
|
|
||||||
//GL.Vertex2(0, 256);
|
|
||||||
|
|
||||||
//GL.End();
|
|
||||||
|
|
||||||
//GL.Translate(0, 256, 0);
|
|
||||||
|
|
||||||
// Build layout
|
|
||||||
int current = 0;
|
|
||||||
foreach (Glyph glyph in block)
|
|
||||||
{
|
{
|
||||||
if (glyph.IsWhiteSpace)
|
//GL.BindTexture(TextureTarget.Texture2D, 2);
|
||||||
|
|
||||||
|
//GL.Begin(BeginMode.Quads);
|
||||||
|
|
||||||
|
//GL.TexCoord2(0, 0);
|
||||||
|
//GL.Vertex2(0, 0);
|
||||||
|
//GL.TexCoord2(1, 0);
|
||||||
|
//GL.Vertex2(256, 0);
|
||||||
|
//GL.TexCoord2(1, 1);
|
||||||
|
//GL.Vertex2(256, 256);
|
||||||
|
//GL.TexCoord2(0, 1);
|
||||||
|
//GL.Vertex2(0, 256);
|
||||||
|
|
||||||
|
//GL.End();
|
||||||
|
|
||||||
|
//GL.Translate(0, 256, 0);
|
||||||
|
|
||||||
|
// Build layout
|
||||||
|
int current = 0;
|
||||||
|
foreach (Glyph glyph in block)
|
||||||
{
|
{
|
||||||
current++;
|
if (glyph.IsWhiteSpace)
|
||||||
continue;
|
{
|
||||||
}
|
current++;
|
||||||
else if (!cache.Contains(glyph))
|
continue;
|
||||||
cache.Add(glyph);
|
}
|
||||||
|
else if (!cache.Contains(glyph))
|
||||||
|
cache.Add(glyph);
|
||||||
|
|
||||||
CachedGlyphInfo info = cache[glyph];
|
CachedGlyphInfo info = cache[glyph];
|
||||||
RectangleF position = extents[current++];
|
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))
|
// Use the real glyph width instead of the measured one (we want to achieve pixel perfect output).
|
||||||
if (inactive_lists.Count > 0)
|
position.Size = info.Rectangle.Size;
|
||||||
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));
|
if (!active_lists.ContainsKey(info.Texture))
|
||||||
active_lists[info.Texture].Add(new Vector2(position.Right, position.Bottom));
|
if (inactive_lists.Count > 0)
|
||||||
active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Top));
|
active_lists.Add(info.Texture, inactive_lists.Dequeue());
|
||||||
active_lists[info.Texture].Add(new Vector2(position.Right, position.Top));
|
else
|
||||||
active_lists[info.Texture].Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top));
|
active_lists.Add(info.Texture, new List<Vector2>());
|
||||||
active_lists[info.Texture].Add(new Vector2(position.Left, position.Top));
|
{
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ using System.Drawing.Text;
|
||||||
using OpenTK.Graphics.Text;
|
using OpenTK.Graphics.Text;
|
||||||
using OpenTK.Platform;
|
using OpenTK.Platform;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
|
||||||
namespace OpenTK.Graphics.Text
|
namespace OpenTK.Graphics.Text
|
||||||
{
|
{
|
||||||
|
@ -47,11 +48,11 @@ namespace OpenTK.Graphics.Text
|
||||||
IntPtr[] regions = new IntPtr[GdiPlus.MaxMeasurableCharacterRanges];
|
IntPtr[] regions = new IntPtr[GdiPlus.MaxMeasurableCharacterRanges];
|
||||||
CharacterRange[] characterRanges = new CharacterRange[GdiPlus.MaxMeasurableCharacterRanges];
|
CharacterRange[] characterRanges = new CharacterRange[GdiPlus.MaxMeasurableCharacterRanges];
|
||||||
|
|
||||||
TextExtents extents = new TextExtents();
|
|
||||||
|
|
||||||
Bitmap glyph_surface;
|
Bitmap glyph_surface;
|
||||||
System.Drawing.Graphics glyph_renderer;
|
System.Drawing.Graphics glyph_renderer;
|
||||||
|
|
||||||
|
readonly ObjectPool<PoolableTextExtents> text_extents_pool = new ObjectPool<PoolableTextExtents>();
|
||||||
|
|
||||||
// Check the constructor, too, for additional flags.
|
// Check the constructor, too, for additional flags.
|
||||||
static readonly StringFormat default_string_format = StringFormat.GenericTypographic;
|
static readonly StringFormat default_string_format = StringFormat.GenericTypographic;
|
||||||
static readonly StringFormat load_glyph_string_format = StringFormat.GenericDefault;
|
static readonly StringFormat load_glyph_string_format = StringFormat.GenericDefault;
|
||||||
|
@ -78,6 +79,8 @@ namespace OpenTK.Graphics.Text
|
||||||
|
|
||||||
public Bitmap Rasterize(Glyph glyph)
|
public Bitmap Rasterize(Glyph glyph)
|
||||||
{
|
{
|
||||||
|
RectangleF r = MeasureText(new TextBlock(glyph.Character.ToString(), glyph.Font, TextPrinterOptions.NoCache, RectangleF.Empty)).BoundingBox;
|
||||||
|
|
||||||
EnsureSurfaceSize(ref glyph_surface, ref glyph_renderer, glyph.Font);
|
EnsureSurfaceSize(ref glyph_surface, ref glyph_renderer, glyph.Font);
|
||||||
|
|
||||||
SetTextRenderingOptions(glyph_renderer, glyph.Font);
|
SetTextRenderingOptions(glyph_renderer, glyph.Font);
|
||||||
|
@ -85,7 +88,25 @@ namespace OpenTK.Graphics.Text
|
||||||
glyph_renderer.Clear(Color.Transparent);
|
glyph_renderer.Clear(Color.Transparent);
|
||||||
glyph_renderer.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty,
|
glyph_renderer.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty,
|
||||||
glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format);
|
glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format);
|
||||||
return glyph_surface.Clone(FindEdges(glyph_surface), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
|
||||||
|
RectangleF r2 = FindEdges(glyph_surface);
|
||||||
|
|
||||||
|
return glyph_surface.Clone(r2, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rasterize(Glyph glyph, ref Bitmap bmp, out Rectangle rect)
|
||||||
|
{
|
||||||
|
EnsureSurfaceSize(ref bmp, ref glyph_renderer, glyph.Font);
|
||||||
|
|
||||||
|
using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp))
|
||||||
|
{
|
||||||
|
SetTextRenderingOptions(gfx, glyph.Font);
|
||||||
|
|
||||||
|
gfx.Clear(Color.Transparent);
|
||||||
|
gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty,
|
||||||
|
glyph.Font.Style == FontStyle.Italic ? load_glyph_string_format : default_string_format);
|
||||||
|
rect = FindEdges(bmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -99,10 +120,10 @@ namespace OpenTK.Graphics.Text
|
||||||
if (block_cache.ContainsKey(block))
|
if (block_cache.ContainsKey(block))
|
||||||
return block_cache[block];
|
return block_cache[block];
|
||||||
|
|
||||||
// If this block is not cached, we have to measure it and place it in the cache.
|
// If this block is not cached, we have to measure it and (potentially) place it in the cache.
|
||||||
MeasureTextExtents(block, ref extents);
|
TextExtents extents = MeasureTextExtents(block);
|
||||||
if ((block.Options & TextPrinterOptions.NoCache) == 0)
|
if ((block.Options & TextPrinterOptions.NoCache) == 0)
|
||||||
block_cache.Add(block, new TextExtents(extents.BoundingBox, extents.GlyphExtents));
|
block_cache.Add(block, extents);
|
||||||
|
|
||||||
return extents;
|
return extents;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +168,7 @@ namespace OpenTK.Graphics.Text
|
||||||
|
|
||||||
#region MeasureTextExtents
|
#region MeasureTextExtents
|
||||||
|
|
||||||
void MeasureTextExtents(TextBlock block, ref TextExtents extents)
|
TextExtents MeasureTextExtents(TextBlock block)
|
||||||
{
|
{
|
||||||
// Todo: Parse layout options:
|
// Todo: Parse layout options:
|
||||||
StringFormat format = default_string_format;
|
StringFormat format = default_string_format;
|
||||||
|
@ -156,7 +177,7 @@ namespace OpenTK.Graphics.Text
|
||||||
//else
|
//else
|
||||||
// format = default_string_format;
|
// format = default_string_format;
|
||||||
|
|
||||||
extents.Clear();
|
TextExtents extents = text_extents_pool.Acquire();
|
||||||
|
|
||||||
PointF origin = PointF.Empty;
|
PointF origin = PointF.Empty;
|
||||||
SizeF size = SizeF.Empty;
|
SizeF size = SizeF.Empty;
|
||||||
|
@ -189,6 +210,8 @@ namespace OpenTK.Graphics.Text
|
||||||
}
|
}
|
||||||
|
|
||||||
extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, extents[extents.Count - 1].Right, extents[extents.Count - 1].Bottom);
|
extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, extents[extents.Count - 1].Right, extents[extents.Count - 1].Bottom);
|
||||||
|
|
||||||
|
return extents;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -252,13 +275,28 @@ namespace OpenTK.Graphics.Text
|
||||||
|
|
||||||
#region FindEdges
|
#region FindEdges
|
||||||
|
|
||||||
|
#pragma warning disable 0649
|
||||||
|
|
||||||
|
struct Pixel { public byte B, G, R, A; }
|
||||||
|
|
||||||
|
#pragma warning restore 0649
|
||||||
|
|
||||||
Rectangle FindEdges(Bitmap bmp)
|
Rectangle FindEdges(Bitmap bmp)
|
||||||
{
|
{
|
||||||
return Rectangle.FromLTRB(
|
BitmapData data = bmp.LockBits(
|
||||||
FindLeftEdge(bmp),
|
new Rectangle(0, 0, bmp.Width, bmp.Height),
|
||||||
FindTopEdge(bmp),
|
ImageLockMode.ReadOnly,
|
||||||
FindRightEdge(bmp),
|
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||||
FindBottomEdge(bmp));
|
|
||||||
|
Rectangle rect = Rectangle.FromLTRB(
|
||||||
|
FindLeftEdge(bmp, data.Scan0),
|
||||||
|
FindTopEdge(bmp, data.Scan0),
|
||||||
|
FindRightEdge(bmp, data.Scan0),
|
||||||
|
FindBottomEdge(bmp, data.Scan0));
|
||||||
|
|
||||||
|
bmp.UnlockBits(data);
|
||||||
|
|
||||||
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -267,34 +305,40 @@ namespace OpenTK.Graphics.Text
|
||||||
|
|
||||||
// Iterates through the bmp, and returns the first row or line that contains a non-transparent pixels.
|
// Iterates through the bmp, and returns the first row or line that contains a non-transparent pixels.
|
||||||
|
|
||||||
int FindLeftEdge(Bitmap bmp)
|
int FindLeftEdge(Bitmap bmp, IntPtr ptr)
|
||||||
{
|
{
|
||||||
// Don't trim the left edge, because the layout engine expects it to be 0.
|
// Don't trim the left edge, because the layout engine expects it to be 0.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FindRightEdge(Bitmap bmp)
|
int FindRightEdge(Bitmap bmp, IntPtr ptr)
|
||||||
{
|
{
|
||||||
for (int x = bmp.Width - 1; x >= 0; x--)
|
for (int x = bmp.Width - 1; x >= 0; x--)
|
||||||
for (int y = 0; y < bmp.Height; y++)
|
for (int y = 0; y < bmp.Height; y++)
|
||||||
if (bmp.GetPixel(x, y).A != 0)
|
unsafe
|
||||||
return x + 1;
|
{
|
||||||
|
if (((Pixel*)(ptr) + y * bmp.Width + x)->A != 0)
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FindTopEdge(Bitmap bmp)
|
int FindTopEdge(Bitmap bmp, IntPtr ptr)
|
||||||
{
|
{
|
||||||
// Don't trim the top edge, because the layout engine expects it to be 0.
|
// Don't trim the top edge, because the layout engine expects it to be 0.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FindBottomEdge(Bitmap bmp)
|
int FindBottomEdge(Bitmap bmp, IntPtr ptr)
|
||||||
{
|
{
|
||||||
for (int y = bmp.Height - 1; y >= 0; y--)
|
for (int y = bmp.Height - 1; y >= 0; y--)
|
||||||
for (int x = 0; x < bmp.Width; x++)
|
for (int x = 0; x < bmp.Width; x++)
|
||||||
if (bmp.GetPixel(x, y).A != 0)
|
unsafe
|
||||||
return y + 1;
|
{
|
||||||
|
if (((Pixel*)(ptr) + y * bmp.Width + x)->A != 0)
|
||||||
|
return y + 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,5 +38,6 @@ namespace OpenTK.Graphics.Text
|
||||||
{
|
{
|
||||||
Bitmap Rasterize(Glyph glyph);
|
Bitmap Rasterize(Glyph glyph);
|
||||||
TextExtents MeasureText(TextBlock block);
|
TextExtents MeasureText(TextBlock block);
|
||||||
|
void Rasterize(Glyph glyph, ref Bitmap bmp, out Rectangle rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
42
Source/Utilities/Graphics/Text/PoolableTextExtents.cs
Normal file
42
Source/Utilities/Graphics/Text/PoolableTextExtents.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,31 +33,21 @@ using System.Drawing;
|
||||||
namespace OpenTK.Graphics.Text
|
namespace OpenTK.Graphics.Text
|
||||||
{
|
{
|
||||||
// Holds layout information about a TextBlock.
|
// Holds layout information about a TextBlock.
|
||||||
public struct TextExtents
|
public class TextExtents : IDisposable
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
RectangleF text_extents;
|
protected RectangleF text_extents;
|
||||||
List<RectangleF> glyph_extents;
|
protected List<RectangleF> glyph_extents = new List<RectangleF>();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public TextExtents(RectangleF bbox)
|
internal TextExtents()
|
||||||
: this(bbox, null)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextExtents(RectangleF bbox, IEnumerable<RectangleF> glyphExtents)
|
|
||||||
: this()
|
|
||||||
{
|
|
||||||
BoundingBox = bbox;
|
|
||||||
|
|
||||||
if (glyphExtents != null)
|
|
||||||
AddRange(glyphExtents);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Members
|
#region Public Members
|
||||||
|
@ -70,23 +60,29 @@ namespace OpenTK.Graphics.Text
|
||||||
|
|
||||||
public RectangleF this[int i]
|
public RectangleF this[int i]
|
||||||
{
|
{
|
||||||
get { return (GlyphExtents as List<RectangleF>)[i]; }
|
get { return glyph_extents[i]; }
|
||||||
internal set { (GlyphExtents as List<RectangleF>)[i] = value; }
|
internal set { glyph_extents[i] = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<RectangleF> GlyphExtents
|
public IEnumerable<RectangleF> GlyphExtents
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (glyph_extents == null)
|
|
||||||
glyph_extents = new List<RectangleF>();
|
|
||||||
return (IEnumerable<RectangleF>)glyph_extents;
|
return (IEnumerable<RectangleF>)glyph_extents;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
get { return (GlyphExtents as List<RectangleF>).Count; }
|
get { return glyph_extents.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextExtents Clone()
|
||||||
|
{
|
||||||
|
TextExtents extents = new TextExtents();
|
||||||
|
extents.glyph_extents.AddRange(GlyphExtents);
|
||||||
|
extents.BoundingBox = BoundingBox;
|
||||||
|
return extents;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -95,18 +91,26 @@ namespace OpenTK.Graphics.Text
|
||||||
|
|
||||||
internal void Add(RectangleF glyphExtent)
|
internal void Add(RectangleF glyphExtent)
|
||||||
{
|
{
|
||||||
(GlyphExtents as List<RectangleF>).Add(glyphExtent);
|
glyph_extents.Add(glyphExtent);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddRange(IEnumerable<RectangleF> glyphExtents)
|
internal void AddRange(IEnumerable<RectangleF> glyphExtents)
|
||||||
{
|
{
|
||||||
(GlyphExtents as List<RectangleF>).AddRange(glyphExtents);
|
glyph_extents.AddRange(glyphExtents);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Clear()
|
internal void Clear()
|
||||||
{
|
{
|
||||||
BoundingBox = RectangleF.Empty;
|
BoundingBox = RectangleF.Empty;
|
||||||
(GlyphExtents as List<RectangleF>).Clear();
|
glyph_extents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
17
Source/Utilities/IPoolable.cs
Normal file
17
Source/Utilities/IPoolable.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
42
Source/Utilities/ObjectPool.cs
Normal file
42
Source/Utilities/ObjectPool.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue