Added missing files from working copy.

This commit is contained in:
the_fiddler 2008-11-24 18:03:47 +00:00
parent 5e449dabd4
commit 18cb4d2432
2 changed files with 469 additions and 0 deletions

View file

@ -0,0 +1,201 @@
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 : IGraphicsResource
{
#region Fields
GraphicsContext context;
int id;
int width, height;
bool disposed;
#endregion
#region Constructors
/// <summary>
/// Constructs a new Texture.
/// </summary>
public AlphaTexture2D(int width, int height)
{
Width = width;
Height = height;
}
#endregion
#region IGraphicsResource Members
GraphicsContext IGraphicsResource.Context { get { return context; } }
int IGraphicsResource.Id
{
get
{
if (id == 0)
{
GraphicsContext.Assert();
context = GraphicsContext.CurrentContext;
id = GL.GenTexture();
if (id == 0)
throw new GraphicsResourceException(String.Format("Texture creation failed, (Error: {0})", GL.GetError()));
// 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);
}
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Alpha, Width, Height, 0,
OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
}
return id;
}
}
#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 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 = bitmap.LockBits(source, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.PushClientAttrib(ClientAttribMask.ClientPixelStoreBit);
try
{
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.Rgba,
PixelType.UnsignedByte, data.Scan0);
}
finally
{
GL.PopClientAttrib();
}
bitmap.UnlockBits(data);
}
public void WriteRegion(TextureRegion2D region, int mipLevel)
{
if (mipLevel < 0)
throw new ArgumentOutOfRangeException("miplevel");
GL.TexSubImage2D(TextureTarget.Texture2D, mipLevel,
region.Rectangle.X, region.Rectangle.Y,
region.Rectangle.Width, region.Rectangle.Height,
PixelFormat.Bgra, PixelType.UnsignedByte, region);
}
#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 Bind
public void Bind()
{
GL.BindTexture(TextureTarget.Texture2D, (this as IGraphicsResource).Id);
}
#endregion
#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;
}
}
~AlphaTexture2D()
{
GraphicsContext context = (this as IGraphicsResource).Context;
if (context != null)
(context as IGraphicsContextInternal).RegisterForDisposal(this);
}
#endregion
}
}

View file

@ -0,0 +1,268 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Text;
using OpenTK.Graphics.Text;
using OpenTK.Platform;
using System.Diagnostics;
namespace OpenTK.Graphics.Text
{
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];
TextExtents extents = new TextExtents();
// Check the constructor, too, for additional flags.
static readonly StringFormat default_string_format = StringFormat.GenericTypographic;
static readonly StringFormat load_glyph_string_format = StringFormat.GenericDefault;
static readonly char[] newline_characters = new char[] { '\n', '\r' };
#endregion
#region Constructors
static GdiPlusGlyphRasterizer()
{
default_string_format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
}
public GdiPlusGlyphRasterizer()
{ }
#endregion
#region IGlyphRasterizer Members
#region Rasterize
public Bitmap Rasterize(Glyph glyph)
{
using (Bitmap bmp = new Bitmap((int)(2 * glyph.Font.Size), (int)(2 * glyph.Font.Size)))
using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp))
{
// Small sizes look blurry without gridfitting, so turn that on.
if (glyph.Font.Size <= 18.0f)
gfx.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
else
gfx.TextRenderingHint = TextRenderingHint.AntiAlias;
gfx.Clear(Color.Transparent);
gfx.DrawString(glyph.Character.ToString(), glyph.Font, Brushes.White, PointF.Empty);
Rectangle tight_rect = FindEdges(bmp);
Bitmap tight_glyph = bmp.Clone(tight_rect, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
//new Bitmap(tight_rect.Width, tight_rect.Height);
//return bmp.Clone(FindEdges(bmp), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
return tight_glyph;
}
}
#endregion
#region MeasureText
//public RectangleF MeasureText(TextBlock block)
//{
// return MeasureText(block, ref extents);
//}
public TextExtents MeasureText(TextBlock block)
{
// 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 place it in the cache.
MeasureTextExtents(block, ref extents);
if ((block.Options & TextPrinterOptions.NoCache) == 0)
block_cache.Add(block, new TextExtents(extents.BoundingBox, extents.GlyphExtents));
return extents;
}
#endregion
#region MeasureGlyph
public RectangleF MeasureGlyph(Glyph glyph)
{
using (Bitmap bmp = Rasterize(glyph))
{
return FindEdges(bmp);
}
}
#endregion
#endregion
#region Private Members
#region MeasureTextExtents
void MeasureTextExtents(TextBlock block, ref TextExtents extents)
{
// Todo: Parse layout options:
StringFormat format = default_string_format;
extents.Clear();
PointF origin = PointF.Empty;
SizeF size = SizeF.Empty;
IntPtr native_graphics = GdiPlus.GetNativeGraphics(graphics);
IntPtr native_font = GdiPlus.GetNativeFont(block.Font);
IntPtr native_string_format = GdiPlus.GetNativeStringFormat(format);
int 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)
{
extents.AddRange(MeasureGlyphExtents(
s, height, 0, s.Length, block.LayoutRectangle,
native_graphics, native_font, native_string_format));
height += block.Font.Height;
}
}
extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, extents[extents.Count - 1].Right, extents[extents.Count - 1].Bottom);
}
#endregion
#region MeasureGlyphExtents
// Gets the bounds of each character in a line of text.
// The line is processed in blocks of 32 characters (GdiPlus.MaxMeasurableCharacterRanges).
IEnumerable<RectangleF> MeasureGlyphExtents(string text, int height, int line_start, int line_length,
RectangleF layoutRect, IntPtr native_graphics, IntPtr native_font, IntPtr native_string_format)
{
RectangleF rect = new RectangleF();
int line_end = line_start + line_length;
while (line_start < line_end)
{
//if (text[line_start] == '\n' || text[line_start] == '\r')
//{
// line_start++;
// continue;
//}
int num_characters = (line_end - line_start) > GdiPlus.MaxMeasurableCharacterRanges ?
GdiPlus.MaxMeasurableCharacterRanges :
line_end - line_start;
int status = 0;
for (int i = 0; i < num_characters; i++)
{
characterRanges[i] = new CharacterRange(line_start + 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));
for (int i = 0; i < num_characters; i++)
{
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));
rect.Y += height;
yield return rect;
}
line_start += num_characters;
}
}
#endregion
#region FindEdges
Rectangle FindEdges(Bitmap bmp)
{
return Rectangle.FromLTRB(
FindLeftEdge(bmp),
FindTopEdge(bmp),
FindRightEdge(bmp),
FindBottomEdge(bmp));
}
#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)
{
for (int x = 0; x < bmp.Width; x++)
for (int y = 0; y < bmp.Height; y++)
if (bmp.GetPixel(x, y).A != 0)
return x;
return bmp.Width;
}
int FindRightEdge(Bitmap bmp)
{
for (int x = bmp.Width - 1; x >= 0; x--)
for (int y = 0; y < bmp.Height; y++)
if (bmp.GetPixel(x, y).A != 0)
return x + 1;
return 0;
}
int FindTopEdge(Bitmap bmp)
{
// Don't trim the top edge, because the layout engine expects it to be 0.
return 0;
}
int FindBottomEdge(Bitmap bmp)
{
for (int y = bmp.Height - 1; y >= 0; y--)
for (int x = 0; x < bmp.Width; x++)
if (bmp.GetPixel(x, y).A != 0)
return y + 1;
return 0;
}
#endregion
#endregion
}
}