[slimdx] r2197 committed - Refactoring of the font system.

13 views
Skip to first unread message

sli...@googlecode.com

unread,
Mar 24, 2012, 9:38:59 PM3/24/12
to slimdx...@googlegroups.com
Revision: 2197
Author: mike.popoloski
Date: Sat Mar 24 18:37:53 2012
Log: Refactoring of the font system.
http://code.google.com/p/slimdx/source/detail?r=2197

Added:
/branches/lite/SlimDX.Toolkit/Fonts/Internal
/branches/lite/SlimDX.Toolkit/Fonts/Internal/FontShaders.cs
/branches/lite/SlimDX.Toolkit/Fonts/Internal/GlyphAtlas.cs
/branches/lite/SlimDX.Toolkit/Fonts/Internal/GlyphImageRenderer.cs
/branches/lite/SlimDX.Toolkit/Fonts/Internal/GlyphProvider.cs
/branches/lite/SlimDX.Toolkit/Fonts/Internal/NativeMethods.cs
/branches/lite/SlimDX.Toolkit/Fonts/Internal/RenderData.cs
/branches/lite/SlimDX.Toolkit/Fonts/Internal/TextRenderer.cs
/branches/lite/SlimDX.Toolkit/Fonts/Internal/VertexDrawer.cs
Deleted:
/branches/lite/SlimDX.Toolkit/Fonts/Geometry
/branches/lite/SlimDX.Toolkit/Fonts/Glyphs
/branches/lite/SlimDX.Toolkit/Fonts/Rendering
Modified:
/branches/lite/SlimDX.Toolkit/Drawing/CommonStates.cs
/branches/lite/SlimDX.Toolkit/Drawing/TextureAtlas.cs
/branches/lite/SlimDX.Toolkit/Fonts/CreateOptions.cs
/branches/lite/SlimDX.Toolkit/Fonts/Font.cs
/branches/lite/SlimDX.Toolkit/SlimDX.Toolkit.csproj
/branches/lite/SlimDX.Toolkit/Sprites/SpriteBatch.cs
/branches/lite/SlimDX.Toolkit/Utilities/SharedResourcePool.cs
/branches/lite/source/DataStream.cpp

=======================================
--- /dev/null
+++ /branches/lite/SlimDX.Toolkit/Fonts/Internal/FontShaders.cs Sat Mar 24
18:37:53 2012
@@ -0,0 +1,226 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+using SlimMath;
+using System.Drawing;
+
+namespace SlimDX.Toolkit
+{
+ static class FontShaders
+ {
+ public const string EmptyVertexShader = @"
+struct GSIn {
+ float3 PositionIndex : POSITIONINDEX;
+ float4 GlyphColor : GLYPHCOLOR;
+};
+
+GSIn VS(GSIn Input) {
+ return Input;
+}
+";
+ public const string SimpleVertexShader = @"
+cbuffer ShaderConstants : register(b0) {
+ float4x4 TransformMatrix : packoffset(c0);
+};
+
+struct VSIn {
+ float4 Position : POSITION;
+ float4 GlyphColor : GLYPHCOLOR;
+};
+
+struct VSOut {
+ float4 Position : SV_Position;
+ float4 GlyphColor : COLOR;
+ float2 TexCoord : TEXCOORD;
+};
+
+VSOut VS(VSIn Input) {
+ VSOut Output;
+
+ Output.Position = mul(TransformMatrix, float4(Input.Position.xy, 0.0f,
1.0f));
+ Output.GlyphColor = Input.GlyphColor;
+ Output.TexCoord = Input.Position.zw;
+
+ return Output;
+}
+";
+ public const string ClippingVertexShader = @"
+cbuffer ShaderConstants : register(b0) {
+ float4x4 TransformMatrix : packoffset(c0);
+ float4 ClipRect : packoffset(c4);
+};
+
+struct VSIn {
+ float4 Position : POSITION;
+ float4 GlyphColor : GLYPHCOLOR;
+};
+
+struct VSOut {
+ float4 Position : SV_Position;
+ float4 GlyphColor : COLOR;
+ float2 TexCoord : TEXCOORD;
+ float4 ClipDistance : CLIPDISTANCE;
+};
+
+VSOut VS(VSIn Input) {
+ VSOut Output;
+
+ Output.Position = mul(TransformMatrix, float4(Input.Position.xy, 0.0f,
1.0f));
+ Output.GlyphColor = Input.GlyphColor;
+ Output.TexCoord = Input.Position.zw;
+ Output.ClipDistance = ClipRect + float4(Input.Position.xy,
-Input.Position.xy);
+
+ return Output;
+}
+";
+ public const string SimpleGeometryShader = @"
+cbuffer ShaderConstants : register(b0) {
+ float4x4 TransformMatrix : packoffset(c0);
+};
+
+Buffer<float4> tex0 : register(t0);
+
+struct GSIn {
+ float3 PositionIndex : POSITIONINDEX;
+ float4 GlyphColor : GLYPHCOLOR;
+};
+
+struct GSOut {
+ float4 Position : SV_Position;
+ float4 GlyphColor : COLOR;
+ float2 TexCoord : TEXCOORD;
+};
+
+[maxvertexcount(4)]
+void GS(point GSIn Input[1], inout TriangleStream<GSOut> TriStream) {
+ const float2 basePosition = Input[0].PositionIndex.xy;
+ const uint glyphIndex = asuint(Input[0].PositionIndex.z);
+
+ float4 texCoords = tex0.Load(uint2(glyphIndex*2, 0));
+ float4 offsets = tex0.Load(uint2(glyphIndex*2+1, 0));
+
+ GSOut Output;
+ Output.GlyphColor = Input[0].GlyphColor;
+
+ float4 positions = basePosition.xyxy + offsets;
+
+ Output.Position = mul(TransformMatrix, float4(positions.xy, 0.0f, 1.0f));
+ Output.TexCoord = texCoords.xy;
+ TriStream.Append(Output);
+
+ Output.Position = mul(TransformMatrix, float4(positions.zy, 0.0f, 1.0f));
+ Output.TexCoord = texCoords.zy;
+ TriStream.Append(Output);
+
+ Output.Position = mul(TransformMatrix, float4(positions.xw, 0.0f, 1.0f));
+ Output.TexCoord = texCoords.xw;
+ TriStream.Append(Output);
+
+ Output.Position = mul(TransformMatrix, float4(positions.zw, 0.0f, 1.0f));
+ Output.TexCoord = texCoords.zw;
+ TriStream.Append(Output);
+
+ TriStream.RestartStrip();
+}
+";
+ public const string ClippingGeometryShader = @"
+cbuffer ShaderConstants : register(b0) {
+ float4x4 TransformMatrix : packoffset(c0);
+ float4 ClipRect : packoffset(c4);
+};
+
+Buffer<float4> tex0 : register(t0);
+
+struct GSIn {
+ float3 PositionIndex : POSITIONINDEX;
+ float4 GlyphColor : GLYPHCOLOR;
+};
+
+struct GSOut {
+ float4 Position : SV_Position;
+ float4 GlyphColor : COLOR;
+ float2 TexCoord : TEXCOORD;
+ float4 ClipDistance : SV_ClipDistance;
+};
+
+[maxvertexcount(4)]
+void GS(point GSIn Input[1], inout TriangleStream<GSOut> TriStream) {
+ const float2 basePosition = Input[0].PositionIndex.xy;
+ const uint glyphIndex = asuint(Input[0].PositionIndex.z);
+
+ float4 texCoords = tex0.Load(uint2(glyphIndex*2, 0));
+ float4 offsets = tex0.Load(uint2(glyphIndex*2+1, 0));
+
+ GSOut Output;
+ Output.GlyphColor = Input[0].GlyphColor;
+
+ float4 positions = basePosition.xyxy + offsets;
+
+ Output.Position = mul(TransformMatrix, float4(positions.xy, 0.0f, 1.0f));
+ Output.TexCoord = texCoords.xy;
+ Output.ClipDistance = ClipRect + float4(positions.xy, -positions.xy);
+ TriStream.Append(Output);
+
+ Output.Position = mul(TransformMatrix, float4(positions.zy, 0.0f, 1.0f));
+ Output.TexCoord = texCoords.zy;
+ Output.ClipDistance = ClipRect + float4(positions.zy, -positions.zy);
+ TriStream.Append(Output);
+
+ Output.Position = mul(TransformMatrix, float4(positions.xw, 0.0f, 1.0f));
+ Output.TexCoord = texCoords.xw;
+ Output.ClipDistance = ClipRect + float4(positions.xw, -positions.xw);
+ TriStream.Append(Output);
+
+ Output.Position = mul(TransformMatrix, float4(positions.zw, 0.0f, 1.0f));
+ Output.TexCoord = texCoords.zw;
+ Output.ClipDistance = ClipRect + float4(positions.zw, -positions.zw);
+ TriStream.Append(Output);
+
+ TriStream.RestartStrip();
+}
+";
+ public const string SimplePixelShader = @"
+SamplerState sampler0 : register(s0);
+Texture2D<float> tex0 : register(t0);
+
+struct PSIn {
+ float4 Position : SV_Position;
+ float4 GlyphColor : COLOR;
+ float2 TexCoord : TEXCOORD;
+};
+
+float4 PS(PSIn Input) : SV_Target {
+ float a = tex0.Sample(sampler0, Input.TexCoord);
+
+ if(a == 0.0f)
+ discard;
+
+ return (a * Input.GlyphColor.a) * float4(Input.GlyphColor.rgb, 1.0f);
+}
+";
+ public const string ClippingPixelShader = @"
+SamplerState sampler0 : register(s0);
+Texture2D<float> tex0 : register(t0);
+
+struct PSIn {
+ float4 Position : SV_Position;
+ float4 GlyphColor : COLOR;
+ float2 TexCoord : TEXCOORD;
+ float4 ClipDistance : CLIPDISTANCE;
+};
+
+float4 PS(PSIn Input) : SV_Target {
+ clip(Input.ClipDistance);
+
+ float a = tex0.Sample(sampler0, Input.TexCoord);
+
+ if(a == 0.0f)
+ discard;
+
+ return (a * Input.GlyphColor.a) * float4(Input.GlyphColor.rgb, 1.0f);
+}
+";
+ }
+}
=======================================
--- /dev/null
+++ /branches/lite/SlimDX.Toolkit/Fonts/Internal/GlyphAtlas.cs Sat Mar 24
18:37:53 2012
@@ -0,0 +1,212 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SlimDX.Direct3D11;
+
+namespace SlimDX.Toolkit
+{
+ struct GlyphBounds
+ {
+ public float OffsetX;
+ public float OffsetY;
+ public int Width;
+ public int Height;
+ }
+
+ class GlyphImageData
+ {
+ public GlyphBounds Metrics;
+ public IntPtr GlyphPixels;
+ public int RowPitch;
+ public int PixelStride;
+ }
+
+ struct GlyphCoords
+ {
+ public float TexCoordLeft;
+ public float TexCoordTop;
+ public float TexCoordRight;
+ public float TexCoordBottom;
+ public float PositionLeft;
+ public float PositionTop;
+ public float PositionRight;
+ public float PositionBottom;
+ }
+
+ // an index into a glyph atlas, including the sheet index and the
texture index within that sheet
+ struct GlyphIndex
+ {
+ public short SheetIndex;
+ public short LocalIndex;
+
+ public bool IsValid
+ {
+ get { return SheetIndex != -1 && LocalIndex != -1; }
+ }
+
+ public GlyphIndex(int value)
+ {
+ SheetIndex = (short)value;
+ LocalIndex = (short)value;
+ }
+
+ public GlyphIndex(int localIndex, int sheetIndex)
+ {
+ SheetIndex = (short)sheetIndex;
+ LocalIndex = (short)localIndex;
+ }
+ }
+
+ /// <summary>
+ /// Maintains a collection of texture atlases for the font glyphs.
+ /// </summary>
+ class GlyphAtlas : IDisposable
+ {
+ Dictionary<GlyphIndex, GlyphCoords> coordinates = new
Dictionary<GlyphIndex, GlyphCoords>();
+ TextureAtlas[] glyphSheets;
+ int currentSheetIndex;
+ int sheetCount;
+ int maxSheetCount = 4096;
+ Device device;
+ int sheetWidth;
+ int sheetHeight;
+ int maxGlyphCount;
+ int flushedSheetIndex;
+
+ public GlyphAtlas(Device device, int sheetWidth, int sheetHeight,
int maxGlyphCount, int maxSheetCount)
+ {
+ this.device = device;
+ this.sheetWidth = sheetWidth;
+ this.sheetHeight = sheetHeight;
+ this.maxGlyphCount = maxGlyphCount;
+
+ if (maxSheetCount > 0 && maxSheetCount < 655536)
+ this.maxSheetCount = maxSheetCount;
+ glyphSheets = new TextureAtlas[this.maxSheetCount];
+
+ // create a default glyph
+ unsafe
+ {
+ byte* glyph0 = stackalloc byte[256];
+ for (int i = 0; i < 256; i++)
+ glyph0[i] = 0xff;
+
+ InsertGlyph(new GlyphImageData
+ {
+ GlyphPixels = new IntPtr(glyph0),
+ RowPitch = 16,
+ PixelStride = 1,
+ Metrics = new GlyphBounds
+ {
+ Width = 16,
+ Height = 16
+ }
+ });
+ }
+ }
+
+ public void Dispose()
+ {
+ if (glyphSheets != null)
+ {
+ foreach (var sheet in glyphSheets)
+ {
+ if (sheet != null)
+ sheet.Dispose();
+ }
+ }
+
+ glyphSheets = null;
+ }
+
+ public void Flush(DeviceContext context)
+ {
+ int first = flushedSheetIndex;
+ flushedSheetIndex = currentSheetIndex;
+
+ for (int i = first; i < sheetCount; i++)
+ glyphSheets[i].Flush(context);
+ }
+
+ public GlyphCoords GetGlyphCoords(GlyphIndex index)
+ {
+ return coordinates[index];
+ }
+
+ public void BindSheet(DeviceContext context, int sheetIndex)
+ {
+ if (sheetIndex < sheetCount)
+ glyphSheets[sheetIndex].Bind(context);
+ }
+
+ public GlyphIndex InsertGlyph(GlyphImageData data)
+ {
+ int sheetIndex = 0;
+ int glyphIndex = -1;
+
+ // attempt to insert the glyph into each sheet that we have
+ for (int i = currentSheetIndex; i < sheetCount; i++)
+ {
+ glyphIndex = glyphSheets[i].AddTexture(data.Metrics.Width,
data.Metrics.Height, data.GlyphPixels, data.RowPitch, data.PixelStride);
+ if (glyphIndex != -1)
+ {
+ sheetIndex = i;
+ break;
+ }
+ }
+
+ // if the glyph didn't fit into any of the sheets we have,
create a new one
+ if (glyphIndex == -1 && sheetCount < maxSheetCount)
+ {
+ var sheet = new TextureAtlas(device, sheetWidth,
sheetHeight, maxGlyphCount, format: DXGI.Format.R8_UNorm);
+ glyphIndex = sheet.AddTexture(data.Metrics.Width,
data.Metrics.Height, data.GlyphPixels, data.RowPitch, data.PixelStride);
+
+ int newSheetIndex = InsertSheet(sheet);
+ if (newSheetIndex != -1)
+ sheetIndex = newSheetIndex;
+ else
+ glyphIndex = -1;
+ }
+
+ if (glyphIndex == -1)
+ return new GlyphIndex(-1);
+
+ var result = new GlyphIndex(glyphIndex, sheetIndex);
+ var coords =
glyphSheets[sheetIndex].GetCoordinates(glyphIndex);
+ coordinates[result] = new GlyphCoords()
+ {
+ PositionLeft = data.Metrics.OffsetX,
+ PositionTop = data.Metrics.OffsetY,
+ PositionRight = data.Metrics.OffsetX + data.Metrics.Width,
+ PositionBottom = data.Metrics.OffsetY +
data.Metrics.Height,
+ TexCoordLeft = coords.Left,
+ TexCoordTop = coords.Top,
+ TexCoordRight = coords.Right,
+ TexCoordBottom = coords.Bottom
+ };
+
+ return result;
+ }
+
+ int InsertSheet(TextureAtlas sheet)
+ {
+ int sheetIndex = -1;
+ if (sheetCount < maxSheetCount)
+ {
+ sheetIndex = sheetCount;
+ glyphSheets[sheetIndex] = sheet;
+ sheetCount++;
+
+ int activeCount = 4;
+ if (sheetCount > currentSheetIndex + activeCount)
+ {
+ glyphSheets[currentSheetIndex].Freeze();
+ currentSheetIndex++;
+ }
+ }
+
+ return sheetIndex;
+ }
+ }
+}
=======================================
--- /dev/null
+++ /branches/lite/SlimDX.Toolkit/Fonts/Internal/GlyphImageRenderer.cs Sat
Mar 24 18:37:53 2012
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SlimDX.DirectWrite;
+using System.Drawing;
+using SlimMath;
+
+namespace SlimDX.Toolkit
+{
+ /// <summary>
+ /// Handles drawing of glyphs as images. Shared between all fonts.
+ /// </summary>
+ class GlyphImageRenderer : IDisposable
+ {
+ Dictionary<RenderingMode, RenderingParameters> parameterMap = new
Dictionary<RenderingMode, RenderingParameters>();
+ IntPtr blackBrush;
+ BitmapRenderTarget renderTarget;
+ int maxWidth = 384;
+ int maxHeight = 384;
+ IntPtr hdc;
+ IntPtr bits;
+ int rowPitch;
+ int stride;
+
+ public GlyphImageRenderer(Factory factory, int renderTargetWidth,
int renderTargetHeight)
+ {
+ if (renderTargetWidth > 0)
+ maxWidth = renderTargetWidth;
+ if (renderTargetHeight > 0)
+ maxHeight = renderTargetHeight;
+
+ using (var interop = factory.GetGdiInterop())
+ {
+ renderTarget =
interop.CreateBitmapRenderTarget(IntPtr.Zero, maxWidth, maxHeight);
+ renderTarget.PixelsPerDip = 1.0f;
+
+ hdc = renderTarget.MemoryDC;
+ blackBrush = NativeMethods.CreateSolidBrush(0);
+
+ var hbitmap = NativeMethods.GetCurrentObject(hdc,
NativeMethods.OBJ_BITMAP);
+ var bitmap = NativeMethods.GetBitmap(hbitmap);
+ bits = bitmap.bmBits;
+ rowPitch = bitmap.bmWidthBytes;
+ stride = bitmap.bmBitsPixel / 8;
+ }
+
+ var modes = new[] { RenderingMode.Default,
RenderingMode.Aliased };
+ foreach (var mode in modes)
+ {
+ var renderingParams =
factory.CreateCustomRenderingParameters(1.0f, 0.0f, 0.0f,
PixelGeometry.Flat, mode);
+ parameterMap.Add(mode, renderingParams);
+ }
+ }
+
+ public void Dispose()
+ {
+ foreach (var value in parameterMap.Values)
+ value.Dispose();
+ parameterMap.Clear();
+
+ if (blackBrush != IntPtr.Zero)
+ NativeMethods.DeleteObject(blackBrush);
+
+ if (renderTarget != null)
+ renderTarget.Dispose();
+
+ blackBrush = IntPtr.Zero;
+ renderTarget = null;
+ }
+
+ public GlyphImageData DrawGlyph(FontFace fontFace, int index,
float fontSize, RenderingMode renderingMode, MeasuringMode measuringMode)
+ {
+ // calculate pixel measurements
+ var indices = new[] { (short)index };
+ var fontMetrics = fontFace.Metrics;
+ var glyphMetrics = fontFace.GetDesignGlyphMetrics(indices,
false);
+ var data = InitGlyphData(fontMetrics, glyphMetrics[0],
fontSize);
+
+ // set up drawing
+ var run = new GlyphRun()
+ {
+ FontFace = fontFace,
+ FontSize = fontSize,
+ GlyphCount = 1,
+ GlyphIndices = indices,
+ GlyphAdvances = new[] { 0.0f },
+ GlyphOffsets = new[] { new GlyphOffset() }
+ };
+
+ // clear the background
+ var br = new NativeMethods.RECT();
+ br.left = br.top = 0;
+ br.right = 2 + data.Width + 5;
+ br.bottom = 2 + data.Height + 5;
+ NativeMethods.FillRect(hdc, ref br, blackBrush);
+
+ RenderingParameters renderingParams;
+ if (!parameterMap.TryGetValue(renderingMode, out
renderingParams))
+ renderingParams = parameterMap[RenderingMode.Default];
+
+ // draw the glyph
+ Rectangle rect;
+ renderTarget.DrawGlyphRun(2.0f - data.OffsetX, 2.0f -
data.OffsetY, measuringMode, run, renderingParams, new Color4(1.0f, 1.0f,
1.0f), out rect);
+
+ // clip to valid render target to avoid buffer overruns in
case the glyph was too large
+ rect.X = Math.Max(rect.X, 0);
+ rect.Y = Math.Max(rect.Y, 0);
+ rect.Width = Math.Min(rect.Width, maxWidth);
+ rect.Height = Math.Min(rect.Height, maxHeight);
+
+ // return the glyph data
+ data.OffsetX += rect.Left - 2.0f;
+ data.OffsetY += rect.Top - 2.0f;
+ data.Width = rect.Width;
+ data.Height = rect.Height;
+
+ var result = new GlyphImageData()
+ {
+ Metrics = data,
+ GlyphPixels = bits + (rect.Y * rowPitch) + (rect.X *
stride),
+ RowPitch = rowPitch,
+ PixelStride = stride
+ };
+
+ return result;
+ }
+
+ GlyphBounds InitGlyphData(FontMetrics fontMetrics, GlyphMetrics
glyphMetrics, float fontSize)
+ {
+ // calculate pixel-space coordinates
+ float fscale = fontSize / fontMetrics.DesignUnitsPerEm;
+ float l = glyphMetrics.LeftSideBearing * fscale;
+ float t = glyphMetrics.TopSideBearing * fscale;
+ float r = glyphMetrics.RightSideBearing * fscale;
+ float b = glyphMetrics.BottomSideBearing * fscale;
+ float v = glyphMetrics.VerticalOrigin * fscale;
+ float aw = glyphMetrics.AdvanceWidth * fscale;
+ float ah = glyphMetrics.AdvanceHeight * fscale;
+
+ var result = new GlyphBounds();
+ result.OffsetX = (float)Math.Floor(l);
+ result.OffsetY = (float)(Math.Floor(t) - Math.Floor(v));
+ result.Width = (int)(aw - r - l + 2.0f);
+ result.Height = (int)(ah - b - t + 2.0f);
+
+ return result;
+ }
+ }
+}
=======================================
--- /dev/null
+++ /branches/lite/SlimDX.Toolkit/Fonts/Internal/GlyphProvider.cs Sat Mar
24 18:37:53 2012
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SlimDX.DirectWrite;
+
+namespace SlimDX.Toolkit
+{
+ using FontKey = Tuple<FontFace, TextOptions, float>;
+ using ResourceKey = Tuple<Factory, int, int>;
+
+ /// <summary>
+ /// Handles rendering glyphs and caching them in an atlas.
+ /// </summary>
+ class GlyphProvider : IDisposable
+ {
+ class GlyphMap : IDisposable
+ {
+ public FontFace FontFace;
+ public float FontSize;
+ public TextOptions Flags;
+ public GlyphIndex[] Glyphs;
+
+ public GlyphMap(FontFace fontFace, float fontSize, TextOptions
flags)
+ {
+ FontFace = fontFace;
+ FontSize = fontSize;
+ Flags = flags;
+
+ int count = fontFace.GlyphCount;
+ Glyphs = new GlyphIndex[count];
+ for (int i = 0; i < count; i++)
+ Glyphs[i] = new GlyphIndex(-1);
+ }
+
+ public void Dispose()
+ {
+ FontFace.Dispose();
+ }
+ }
+
+ static SharedResourcePool<ResourceKey, GlyphImageRenderer>
sharedRenderTargets = new SharedResourcePool<ResourceKey,
GlyphImageRenderer>();
+ static SharedResourcePool<FontKey, GlyphMap> sharedFontMaps = new
SharedResourcePool<FontKey, GlyphMap>();
+
+ Dictionary<FontKey, ISharedResource<GlyphMap>> localFontMaps = new
Dictionary<FontKey, ISharedResource<GlyphMap>>();
+ ISharedResource<GlyphImageRenderer> renderTargetResource;
+ GlyphImageRenderer renderTarget;
+ GlyphAtlas glyphAtlas;
+
+ public GlyphProvider(Factory factory, GlyphAtlas glyphAtlas, int
maxGlyphWidth, int maxGlyphHeight)
+ {
+ this.glyphAtlas = glyphAtlas;
+
+ int renderTargetWidth = 384;
+ if (maxGlyphWidth > 0 && maxGlyphWidth <= 8192)
+ renderTargetWidth = maxGlyphWidth;
+ int renderTargetHeight = 384;
+ if (maxGlyphHeight > 0 && maxGlyphHeight <= 8192)
+ renderTargetHeight = maxGlyphHeight;
+
+ renderTargetResource = sharedRenderTargets.DemandCreate(new
ResourceKey(factory, renderTargetWidth, renderTargetHeight), () => new
GlyphImageRenderer(factory, renderTargetWidth, renderTargetHeight));
+ renderTarget = renderTargetResource.Resource;
+ }
+
+ public void Dispose()
+ {
+ if (renderTargetResource != null)
+ {
+ renderTargetResource.Release();
+ renderTargetResource = null;
+ }
+
+ foreach (var key in localFontMaps.Values)
+ key.Release();
+ localFontMaps.Clear();
+ }
+
+ GlyphMap GetGlyphMapFromFont(FontFace fontFace, float fontSize,
TextOptions flags)
+ {
+ ISharedResource<GlyphMap> resource;
+ var key = new FontKey(fontFace, flags & TextOptions.Aliased,
fontSize);
+ if (localFontMaps.TryGetValue(key, out resource))
+ return resource.Resource;
+
+ if ((flags & TextOptions.NoNewGlyphs) != 0)
+ return null;
+
+ // when creating a new map, insert the default glyph (glyph
zero) to seed the map
+ resource = sharedFontMaps.DemandCreate(key, () => { var map =
new GlyphMap(fontFace, fontSize, flags); InsertNewGlyph(map, 0, fontFace);
return map; });
+ localFontMaps.Add(key, resource);
+
+ return resource.Resource;
+ }
+
+ public GlyphIndex RenderToAtlas(int index, FontFace fontFace,
float fontSize, TextOptions flags)
+ {
+ var map = GetGlyphMapFromFont(fontFace, fontSize, flags);
+ if (map == null || index >= map.Glyphs.Length)
+ return new GlyphIndex(0);
+
+ // try to look up the desired glyph in the map; if it's not
there, create it
+ var atlasId = map.Glyphs[index];
+ if (!atlasId.IsValid && (flags & TextOptions.NoNewGlyphs) == 0)
+ InsertNewGlyph(map, index, fontFace);
+
+ // fallback to the default glyph on failure
+ atlasId = map.Glyphs[index];
+ if (!atlasId.IsValid)
+ atlasId = map.Glyphs[0];
+
+ return atlasId;
+ }
+
+ void InsertNewGlyph(GlyphMap glyphMap, int index, FontFace
fontFace)
+ {
+ var renderingMode = RenderingMode.Default;
+ var measuringMode = MeasuringMode.Natural;
+ if ((glyphMap.Flags & TextOptions.Aliased) != 0)
+ {
+ renderingMode = RenderingMode.Aliased;
+ measuringMode = MeasuringMode.GdiClassic;
+ }
+
+ var data = renderTarget.DrawGlyph(fontFace, index,
glyphMap.FontSize, renderingMode, measuringMode);
+ glyphMap.Glyphs[index] = glyphAtlas.InsertGlyph(data);
+ }
+ }
+}
=======================================
--- /dev/null
+++ /branches/lite/SlimDX.Toolkit/Fonts/Internal/NativeMethods.cs Sat Mar
24 18:37:53 2012
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace SlimDX.Toolkit
+{
+ static class NativeMethods
+ {
+ public const int OBJ_BITMAP = 7;
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int left, top, right, bottom;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct BITMAP
+ {
+ public int bmType;
+ public int bmWidth;
+ public int bmHeight;
+ public int bmWidthBytes;
+ public short bmPlanes;
+ public short bmBitsPixel;
+ public IntPtr bmBits;
+ }
+
+ [DllImport("gdi32.dll")]
+ public static extern IntPtr CreateSolidBrush(uint crColor);
+
+ [DllImport("gdi32.dll")]
+ public static extern bool DeleteObject(IntPtr hObject);
+
+ [DllImport("gdi32.dll")]
+ public static extern IntPtr GetCurrentObject(IntPtr hdc, uint
uObjectType);
+
+ [DllImport("gdi32.dll")]
+ public static extern int GetObject(IntPtr hgdiobj, int cbBuffer,
IntPtr lpvObject);
+
+ [DllImport("user32.dll")]
+ public static extern int FillRect(IntPtr hDC, ref RECT lprc,
IntPtr hbr);
+
+ public static BITMAP GetBitmap(IntPtr hbitmap)
+ {
+ var result = new BITMAP();
+ unsafe { GetObject(hbitmap, Marshal.SizeOf(result), new
IntPtr(&result)); }
+ return result;
+ }
+ }
+}
=======================================
--- /dev/null
+++ /branches/lite/SlimDX.Toolkit/Fonts/Internal/RenderData.cs Sat Mar 24
18:37:53 2012
@@ -0,0 +1,210 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SlimDX.Direct3D11;
+using Buffer = SlimDX.Direct3D11.Buffer;
+using Device = SlimDX.Direct3D11.Device;
+using MapFlags = SlimDX.Direct3D11.MapFlags;
+using System.Drawing;
+using SlimMath;
+using SlimDX.D3DCompiler;
+using SlimDX.DXGI;
+using System.Runtime.InteropServices;
+
+namespace SlimDX.Toolkit
+{
+ class RenderData : IDisposable
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ struct ShaderConstants
+ {
+ public static readonly int SizeInBytes =
Marshal.SizeOf(typeof(ShaderConstants));
+
+ public Matrix Transform;
+ public RectangleF ClipRect;
+ }
+
+ HashSet<IDisposable> resources = new HashSet<IDisposable>(); //
I'm lazy
+ Device device;
+ FeatureLevel featureLevel;
+ VertexShader simpleVertexShader;
+ VertexShader clippingVertexShader;
+ PixelShader simplePixelShader;
+ PixelShader clippingPixelShader;
+ InputLayout inputLayout;
+ ConstantBuffer<ShaderConstants> constantBuffer;
+ BlendState blendState;
+ SamplerState samplerState;
+ DepthStencilState depthStencilState;
+ RasterizerState rasterizerState;
+
+ public RenderData(Device device, bool anisotropicFiltering)
+ {
+ this.device = device;
+ featureLevel = device.FeatureLevel;
+
+ CreateQuadShaders();
+ CreatePixelShaders();
+ CreateConstantBuffer();
+ CreateRenderStates(anisotropicFiltering);
+ }
+
+ public void Dispose()
+ {
+ foreach (var resource in resources)
+ resource.Dispose();
+ resources.Clear();
+ }
+
+ public void SetStates(DeviceContext context, TextOptions flags)
+ {
+ // quads constructed on the CPU
+ context.InputAssembler.PrimitiveTopology =
PrimitiveTopology.TriangleList;
+ context.InputAssembler.InputLayout = inputLayout;
+ context.VertexShader.Set((flags & TextOptions.ClipRect) != 0 ?
clippingVertexShader : simpleVertexShader);
+ context.PixelShader.Set((flags & TextOptions.ClipRect) != 0 ?
clippingPixelShader : simplePixelShader);
+ context.VertexShader.SetConstantBuffer(constantBuffer.Buffer,
0);
+
+ // clear out unused shaders
+ if (featureLevel >= FeatureLevel.Level_10_0)
+ context.GeometryShader.Set(null);
+
+ if (featureLevel >= FeatureLevel.Level_11_0)
+ {
+ context.DomainShader.Set(null);
+ context.HullShader.Set(null);
+ }
+
+ // set render states
+ context.OutputMerger.SetBlendState(blendState, new Color4(0),
-1);
+ context.OutputMerger.SetDepthStencilState(depthStencilState,
0);
+ context.Rasterizer.State = rasterizerState;
+ context.PixelShader.SetSampler(samplerState, 0);
+ }
+
+ public unsafe void UpdateShaderConstants(DeviceContext context,
RectangleF* clipRect, Matrix* transform)
+ {
+ var constants = new ShaderConstants();
+ if (transform != null)
+ constants.Transform = *transform;
+ else
+ {
+ float w = 512.0f;
+ float h = 512.0f;
+
+ var vp = context.Rasterizer.GetViewport();
+ if (vp.Width >= 1.0f && vp.Height >= 1.0f)
+ {
+ w = vp.Width;
+ h = vp.Height;
+ }
+
+ constants.Transform = Matrix.OrthoOffCenterLH(0.0f, w, h,
0.0f, 0.0f, 1.0f);
+ }
+
+ if (clipRect != null)
+ {
+ constants.ClipRect = *clipRect;
+ constants.ClipRect.X *= -1;
+ constants.ClipRect.Y *= -1;
+ }
+ else
+ {
+ constants.ClipRect.X = float.MaxValue;
+ constants.ClipRect.Y = float.MaxValue;
+ constants.ClipRect.Width = float.MaxValue;
+ constants.ClipRect.Height = float.MaxValue;
+ }
+
+ constantBuffer.SetData(context, ref constants);
+ }
+
+ void CreateQuadShaders()
+ {
+ // compile vertex shaders
+ using (var bytecode =
ShaderBytecode.Compile(FontShaders.SimpleVertexShader, "VS",
device.VertexShaderProfile, ShaderFlags.OptimizationLevel3,
EffectFlags.None))
+ {
+ simpleVertexShader = new VertexShader(device, bytecode);
+ inputLayout = new InputLayout(device, bytecode, new[] {
+ new InputElement("POSITION", 0,
Format.R32G32B32A32_Float, 0),
+ new InputElement("GLYPHCOLOR", 0,
Format.R8G8B8A8_UNorm, 0)
+ });
+ }
+
+ using (var bytecode =
ShaderBytecode.Compile(FontShaders.ClippingVertexShader, "VS",
device.VertexShaderProfile, ShaderFlags.OptimizationLevel3,
EffectFlags.None))
+ clippingVertexShader = new VertexShader(device, bytecode);
+
+ resources.Add(simpleVertexShader);
+ resources.Add(inputLayout);
+ resources.Add(clippingVertexShader);
+ }
+
+ void CreatePixelShaders()
+ {
+ // compile pixel shaders
+ using (var bytecode =
ShaderBytecode.Compile(FontShaders.SimplePixelShader, "PS",
device.PixelShaderProfile, ShaderFlags.OptimizationLevel3,
EffectFlags.None))
+ simplePixelShader = new PixelShader(device, bytecode);
+
+ using (var bytecode =
ShaderBytecode.Compile(FontShaders.ClippingPixelShader, "PS",
device.PixelShaderProfile, ShaderFlags.OptimizationLevel3,
EffectFlags.None))
+ clippingPixelShader = new PixelShader(device, bytecode);
+
+ resources.Add(simplePixelShader);
+ resources.Add(clippingPixelShader);
+ }
+
+ void CreateConstantBuffer()
+ {
+ constantBuffer = new ConstantBuffer<ShaderConstants>(device);
+ resources.Add(constantBuffer);
+ }
+
+ void CreateRenderStates(bool anisotropicFiltering)
+ {
+ var blendDesc = new BlendStateDescription();
+ for (int i = 0; i < 4; i++)
+ {
+ blendDesc.RenderTargets[i] = new
RenderTargetBlendDescription
+ {
+ BlendEnable = true,
+ SourceBlend = BlendOption.One,
+ DestinationBlend = BlendOption.InverseSourceAlpha,
+ BlendOperation = BlendOperation.Add,
+ SourceBlendAlpha = BlendOption.One,
+ DestinationBlendAlpha = BlendOption.Zero,
+ BlendOperationAlpha = BlendOperation.Add,
+ RenderTargetWriteMask = ColorWriteMaskFlags.All
+ };
+ }
+
+ blendState = BlendState.FromDescription(device, blendDesc);
+ samplerState = SamplerState.FromDescription(device, new
SamplerDescription
+ {
+ AddressU = TextureAddressMode.Clamp,
+ AddressV = TextureAddressMode.Clamp,
+ AddressW = TextureAddressMode.Clamp,
+ MaximumLod = float.MaxValue,
+ Filter = anisotropicFiltering ? Filter.Anisotropic :
Filter.MinMagMipLinear,
+ MaximumAnisotropy = anisotropicFiltering ? featureLevel >=
FeatureLevel.Level_9_2 ? 5 : 2 : 0
+ });
+
+ rasterizerState = RasterizerState.FromDescription(device, new
RasterizerStateDescription
+ {
+ FillMode = FillMode.Solid,
+ CullMode = CullMode.None,
+ IsFrontCounterclockwise = false,
+ IsDepthClipEnabled = true
+ });
+
+ depthStencilState = DepthStencilState.FromDescription(device,
new DepthStencilStateDescription
+ {
+ IsDepthEnabled = false
+ });
+
+ resources.Add(blendState);
+ resources.Add(samplerState);
+ resources.Add(rasterizerState);
+ resources.Add(depthStencilState);
+ }
+ }
+}
=======================================
--- /dev/null
+++ /branches/lite/SlimDX.Toolkit/Fonts/Internal/TextRenderer.cs Sat Mar 24
18:37:53 2012
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SlimDX.DirectWrite;
+using System.Runtime.InteropServices;
+using SlimMath;
+
+namespace SlimDX.Toolkit
+{
+ // represents a glyph (index into an atlas) rendered at a specified
position with a given color
+ struct GlyphVertex
+ {
+ public Vector2 Position;
+ public GlyphIndex GlyphIndex;
+ public int Color;
+
+ public GlyphVertex(GlyphIndex index, float x, float y, int color)
+ {
+ Position = new Vector2(x, y);
+ GlyphIndex = index;
+ Color = color;
+ }
+ }
+
+ /// <summary>
+ /// Converts formatted spans of text into a list of glyphs and
positions to draw.
+ /// </summary>
+ class TextRenderer : ITextRenderer
+ {
+ GlyphProvider glyphProvider;
+ List<GlyphVertex> vertices = new List<GlyphVertex>();
+ TextOptions currentFlags;
+
+ public TextRenderer(GlyphProvider glyphProvider)
+ {
+ this.glyphProvider = glyphProvider;
+ }
+
+ public void DrawTextLayout(TextLayout layout, float originX, float
originY, int color, TextOptions flags)
+ {
+ vertices.Clear();
+
+ currentFlags = flags;
+ layout.Draw(new IntPtr(color), this, originX, originY);
+ }
+
+ public Result DrawGlyphRun(IntPtr drawingContext, float
baselineOriginX, float baselineOriginY, MeasuringMode measuringMode,
GlyphRun glyphRun, GlyphRunDescription glyphRunDescription, IntPtr
clientDrawingEffect)
+ {
+ // skip if we're not interested in drawing
+ if ((currentFlags & TextOptions.AnalyzeOnly) != 0)
+ return ResultCode.Success;
+
+ int color = drawingContext.ToInt32();
+ float x = (float)Math.Floor(baselineOriginX + 0.5f);
+ float y = (float)Math.Floor(baselineOriginY + 0.5f);
+
+ // go through each glyph in the run and render it into the
atlas
+ for (int i = 0; i < glyphRun.GlyphCount; i++)
+ {
+ var index =
glyphProvider.RenderToAtlas(glyphRun.GlyphIndices[i], glyphRun.FontFace,
glyphRun.FontSize, currentFlags);
+
+ // check if we should draw the vertex or if we just want
to cache the glyphs
+ if ((currentFlags & TextOptions.CacheOnly) == 0)
+ {
+ if ((glyphRun.BidiLevel & 0x1) != 0)
+ x -= glyphRun.GlyphAdvances[i];
+
+ vertices.Add(new GlyphVertex(index, x, y, color));
+
+ if ((glyphRun.BidiLevel & 0x1) == 0)
+ x += glyphRun.GlyphAdvances[i];
+ }
+ }
+
+ return ResultCode.Success;
+ }
+
+ public IList<GlyphVertex> SortVertices()
+ {
+ // group vertices by the sheet they're in
+ vertices.Sort((x, y) =>
x.GlyphIndex.SheetIndex.CompareTo(y.GlyphIndex.SheetIndex));
+ return vertices;
+ }
+
+ #region Default Interface Implementation
+
+ public Result DrawInlineObject(IntPtr drawingContext, float
baselineOriginX, float baselineOriginY, InlineObject inlineObject, bool
isSideways, bool isRightToLeft, IntPtr clientDrawingEffect)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Result DrawStrikethrough(IntPtr drawingContext, float
baselineOriginX, float baselineOriginY, Strikethrough strikethrough, IntPtr
clientDrawingEffect)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Result DrawUnderline(IntPtr drawingContext, float
baselineOriginX, float baselineOriginY, Underline underline, IntPtr
clientDrawingEffect)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Matrix3x2 GetCurrentTransform(IntPtr drawingContext)
+ {
+ return Matrix3x2.Identity;
+ }
+
+ public float GetPixelsPerDip(IntPtr drawingContext)
+ {
+ return 96.0f;
+ }
+
+ public bool IsPixelSnappingDisabled(IntPtr drawingContext)
+ {
+ return false;
+ }
+
+ #endregion
+ }
+}
=======================================
--- /dev/null
+++ /branches/lite/SlimDX.Toolkit/Fonts/Internal/VertexDrawer.cs Sat Mar 24
18:37:53 2012
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using SlimDX.Direct3D11;
+using SlimDX.DXGI;
+using SlimMath;
+using Buffer = SlimDX.Direct3D11.Buffer;
+using Device = SlimDX.Direct3D11.Device;
+using MapFlags = SlimDX.Direct3D11.MapFlags;
+using System.Runtime.InteropServices;
+
+namespace SlimDX.Toolkit
+{
+ /// <summary>
+ /// Handles the drawing of glyphs to textured quads.
+ /// </summary>
+ class VertexDrawer : IDisposable
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ struct QuadVertex
+ {
+ public static readonly int SizeInBytes =
Marshal.SizeOf(typeof(QuadVertex));
+
+ public Vector2 Position;
+ public Vector2 TexCoords;
+ public int Color;
+ }
+
+ Buffer vertexBuffer;
+ Buffer indexBuffer;
+ int bufferSize = 4096 * 16;
+ int maxIndexCount;
+
+ public VertexDrawer(Device device, int vertexBufferSize)
+ {
+ if (vertexBufferSize >= 1024)
+ {
+ if (device.FeatureLevel < FeatureLevel.Level_9_2)
+ vertexBufferSize = Math.Min(vertexBufferSize, 512 *
1024);
+ bufferSize = vertexBufferSize;
+ }
+
+ maxIndexCount = (bufferSize * 3) / (2 *
QuadVertex.SizeInBytes);
+ if (maxIndexCount < 64)
+ maxIndexCount = 64;
+
+ vertexBuffer = new Buffer(device, new BufferDescription
+ {
+ SizeInBytes = bufferSize,
+ Usage = ResourceUsage.Dynamic,
+ BindFlags = BindFlags.VertexBuffer,
+ CpuAccessFlags = CpuAccessFlags.Write
+ });
+
+ using (var indices = new DataStream(sizeof(short) *
maxIndexCount, true, true))
+ {
+ for (int i = 0; i < maxIndexCount / 6; i++)
+ {
+ indices.Write((short)(i * 4));
+ indices.Write((short)(i * 4 + 1));
+ indices.Write((short)(i * 4 + 2));
+ indices.Write((short)(i * 4 + 1));
+ indices.Write((short)(i * 4 + 3));
+ indices.Write((short)(i * 4 + 2));
+ }
+
+ indices.Position = 0;
+ indexBuffer = new Buffer(device, indices, new
BufferDescription
+ {
+ SizeInBytes = sizeof(short) * maxIndexCount,
+ Usage = ResourceUsage.Immutable,
+ BindFlags = BindFlags.IndexBuffer
+ });
+ }
+ }
+
+ public void Dispose()
+ {
+ if (vertexBuffer != null)
+ vertexBuffer.Dispose();
+
+ if (indexBuffer != null)
+ indexBuffer.Dispose();
+
+ vertexBuffer = null;
+ indexBuffer = null;
+ }
+
+ public void DrawVertices(DeviceContext context, GlyphAtlas
glyphAtlas, IList<GlyphVertex> vertexData, TextOptions flags)
+ {
+ if ((flags & TextOptions.BuffersPrepared) == 0)
+ {
+ context.InputAssembler.SetIndexBuffer(indexBuffer,
Format.R16_UInt, 0);
+ context.InputAssembler.SetVertexBuffers(0, new
VertexBufferBinding(vertexBuffer, QuadVertex.SizeInBytes, 0));
+ }
+
+ int maxVertexCount = bufferSize / QuadVertex.SizeInBytes;
+ if (maxVertexCount > 4 * (maxIndexCount / 6))
+ maxVertexCount = 4 * (maxIndexCount / 6);
+ if (maxVertexCount % 4 != 0)
+ maxVertexCount -= (maxVertexCount % 4);
+
+ int current = 0;
+ int total = vertexData.Count;
+
+ // draw every vertex as a 2-tri quad
+ while (current < total)
+ {
+ var data = context.MapSubresource(vertexBuffer,
MapMode.WriteDiscard, MapFlags.None).Data;
+
+ // figure out the number of vertices we can draw in
this "pass" (limited by the size of the vertex buffer)
+ int count = Math.Min(total - current, maxVertexCount / 4);
+ for (int i = 0; i < count; i++)
+ {
+ var vertex = vertexData[current + i];
+ var coords =
glyphAtlas.GetGlyphCoords(vertex.GlyphIndex);
+
+ var output = new QuadVertex();
+ output.Color = vertex.Color;
+ output.Position = vertex.Position + new
Vector2(coords.PositionLeft, coords.PositionTop);
+ output.TexCoords = new Vector2(coords.TexCoordLeft,
coords.TexCoordTop);
+ data.Write(output);
+
+ output.Position.X = vertex.Position.X +
coords.PositionRight;
+ output.TexCoords.X = coords.TexCoordRight;
+ data.Write(output);
+
+ output.Position.Y = vertex.Position.Y +
coords.PositionBottom;
+ output.TexCoords.Y = coords.TexCoordBottom;
+ data.Write(output);
+
+ output.Position.X = vertex.Position.X +
coords.PositionLeft;
+ output.TexCoords.X = coords.TexCoordLeft;
+ data.Write(output);
+ }
+
+ context.UnmapSubresource(vertexBuffer, 0);
+
+ // now draw the vertices (one draw call per sheet)
+ int currentSheet = -1;
+ int sheetCount = 0;
+ int drawn = 0;
+
+ for (int i = 0; i < count; i++)
+ {
+ int sheet = vertexData[current +
i].GlyphIndex.SheetIndex;
+ if (sheet != currentSheet)
+ {
+ if (sheetCount != 0)
+ {
+ glyphAtlas.BindSheet(context, currentSheet);
+ context.DrawIndexed(sheetCount * 6, 0, drawn);
+ drawn += sheetCount * 4;
+ }
+
+ sheetCount = 0;
+ currentSheet = sheet;
+ }
+
+ sheetCount++;
+ }
+
+ current += count;
+ }
+ }
+ }
+}
=======================================
--- /branches/lite/SlimDX.Toolkit/Drawing/CommonStates.cs Mon Mar 19
16:08:39 2012
+++ /branches/lite/SlimDX.Toolkit/Drawing/CommonStates.cs Sat Mar 24
18:37:53 2012
@@ -248,7 +248,11 @@
/// </summary>
public void Dispose()
{
- resource.Dispose();
+ if (resource != null)
+ {
+ resource.Release();
+ resource = null;
+ }
}
}
}
=======================================
--- /branches/lite/SlimDX.Toolkit/Drawing/TextureAtlas.cs Fri Mar 23
16:09:34 2012
+++ /branches/lite/SlimDX.Toolkit/Drawing/TextureAtlas.cs Sat Mar 24
18:37:53 2012
@@ -87,7 +87,7 @@
/// <param name="bytesPerPixel">The number of bytes per pixel in
the texture.</param>
/// <returns>A handle that can be used to retrieve texture
coordinates for the stored texture, or -1 if the texture cannot fit into
the atlas.</returns>
/// <exception cref="InvalidOperationException">Thrown if the
atlas has been frozen.</exception>
- public int AddTexture(int width, int height, DataStream pixelData,
int rowPitch, int bytesPerPixel)
+ public int AddTexture(int width, int height, IntPtr pixelData, int
rowPitch, int bytesPerPixel)
{
if (shouldFreeze || frozen)
throw new InvalidOperationException("Cannot add a texture
to an atlas that has been frozen.");
@@ -113,7 +113,7 @@
position.Y += gutterWidth;
for (int i = 0; i < height && i < sheetHeight -
position.Y; i++)
{
- byte* src = (byte*)pixelData.DataPointer + (i *
rowPitch);
+ byte* src = (byte*)pixelData + (i * rowPitch);
byte* dest = (byte*)textureData.DataPointer +
((position.Y + i) * sheetWidth + position.X) * formatSize;

// copy each pixel into the texture, only copying the
number of bytes that we have support for
=======================================
--- /branches/lite/SlimDX.Toolkit/Fonts/CreateOptions.cs Thu Mar 22
19:09:22 2012
+++ /branches/lite/SlimDX.Toolkit/Fonts/CreateOptions.cs Sat Mar 24
18:37:53 2012
@@ -12,7 +12,7 @@
/// However, the DrawText methods will silently fail if no default
font is set up.<br/>
/// If FontFamily is not <c>null</c>, the FontWeight, FontStyle and
FontStretch members must be set to valid values according to the
DirectWrite documentation.
/// Zero is not a valid value for these.</remarks>
- public class DWriteFontParameters
+ public class DefaultFontParameters
{
/// <summary>The name of the font-family. Valid values include
<i>Arial</i>, <i>Courier New</i>, etc. as long as the specified font is
installed.
/// Unavailable fonts will automatically fall back to a different
font.
@@ -32,10 +32,10 @@
public string Locale { get; set; }

/// <summary>
- /// Initializes a new instance of the <see
cref="DWriteFontParameters"/> class.
+ /// Initializes a new instance of the <see
cref="DefaultFontParameters"/> class.
/// </summary>
/// <param name="fontFamily">The font family.</param>
- public DWriteFontParameters(string fontFamily)
+ public DefaultFontParameters(string fontFamily)
{
FontFamily = fontFamily;
FontWeight = FontWeight.Normal;
@@ -56,9 +56,6 @@

/// <summary>The maximum number of glyphs per texture. A buffer of
<i>MaxGlyphCountPerSheet * 32</i> bytes is preallocated for each sheet. 0
defaults to 2048.</summary>
public int MaxGlyphCountPerSheet { get; set; }
-
- /// <summary>The number of mip-levels for the glyph sheet
textures. 0 defaults to 1.</summary>
- public int SheetMipLevels { get; set; }

/// <summary>If set to <c>true</c>, the sampler-state is created
with anisotropic filtering.</summary>
public bool AnisotropicFiltering { get; set; }
@@ -72,16 +69,13 @@
/// This value is used to decide how large the DirectWrite render
target needs to be, which is used when drawing glyph images to put in the
atlas.
/// 0 defaults to 384.</summary>
public int MaxGlyphHeight { get; set; }
-
- /// <summary>If set to <c>true</c>, no geometry shader is
used.</summary>
- public bool DisableGeometryShader { get; set; }

/// <summary>The size in bytes of the dynamic vertex buffer to
upload glyph vertices to when drawing a string. 0 defaults to 4096 *
16.<br/>
- /// Each glyph vertex is either 16 or 20 bytes in size, and each
glyph requires either 1 or 4 vertices depending on if the geometry shader
is used.</summary>
+ /// Each glyph vertex is either 16 or 20 bytes in size, and each
glyph requires 4 vertices.</summary>
public int VertexBufferSize { get; set; }

- /// <summary>Description of the default font. See
DWriteFontParameters.</summary>
- public DWriteFontParameters DefaultFontParameters { get; set; }
+ /// <summary>Description of the default font. See
DefaultFontParameters.</summary>
+ public DefaultFontParameters DefaultFontParameters { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="CreateOptions"/>
class.
@@ -89,11 +83,10 @@
/// <param name="fontFamily">The font family.</param>
public CreateOptions(string fontFamily)
{
- DefaultFontParameters = new DWriteFontParameters(fontFamily);
+ DefaultFontParameters = new DefaultFontParameters(fontFamily);
GlyphSheetWidth = 512;
GlyphSheetHeight = 512;
MaxGlyphCountPerSheet = 2048;
- SheetMipLevels = 1;
MaxGlyphWidth = 384;
MaxGlyphHeight = 384;
}
=======================================
--- /branches/lite/SlimDX.Toolkit/Fonts/Font.cs Thu Mar 22 19:09:22 2012
+++ /branches/lite/SlimDX.Toolkit/Fonts/Font.cs Sat Mar 24 18:37:53 2012
@@ -4,7 +4,6 @@
using System.Text;
using SlimDX.DirectWrite;
using SlimDX.Direct3D11;
-using SlimDX.Toolkit.Fonts;
using System.Drawing;
using SlimMath;

@@ -45,9 +44,6 @@
/// <summary>If a clip-rect is specified together with this flag,
all text is clipped to inside the specified rectangle.</summary>
ClipRect = 0x40,

- /// <summary>No geometry shader is used when drawing glyphs.
Indexed quads are constructed on the CPU instead of in the geometry
shader.</summary>
- NoGeometryShader = 0x80,
-
/// <summary>The transform matrix and the clip-rect is not updated
in the internal constant-buffer. Can be used as an optimization when a
previous call has already set the correct data.</summary>
ConstantsPrepared = 0x100,

@@ -89,7 +85,6 @@
GlyphAtlas glyphAtlas;
TextFormat defaultFormat;
TextRenderer renderer;
- TextGeometry geometry;
FeatureLevel featureLevel;
RenderData renderStates;
VertexDrawer glyphDrawer;
@@ -115,11 +110,10 @@
{
this.factory = factory;
featureLevel = device.FeatureLevel;
- glyphAtlas = new GlyphAtlas(device, options.GlyphSheetWidth,
options.GlyphSheetHeight, !options.DisableGeometryShader, true,
options.MaxGlyphCountPerSheet, options.SheetMipLevels, 4096);
+ glyphAtlas = new GlyphAtlas(device, options.GlyphSheetWidth,
options.GlyphSheetHeight, options.MaxGlyphCountPerSheet, 4096);
glyphProvider = new GlyphProvider(factory, glyphAtlas,
options.MaxGlyphWidth, options.MaxGlyphHeight);
glyphDrawer = new VertexDrawer(device,
options.VertexBufferSize);
- renderStates = new
RenderData(device, !options.DisableGeometryShader,
options.AnisotropicFiltering);
- geometry = new TextGeometry();
+ renderStates = new RenderData(device,
options.AnisotropicFiltering);
renderer = new TextRenderer(glyphProvider);

if
(!string.IsNullOrEmpty(options.DefaultFontParameters.FontFamily))
@@ -208,10 +202,8 @@
/// <param name="flags">Text rendering flags.</param>
public void DrawText(DeviceContext context, string text, string
fontFamily, float size, RectangleF layoutBounds, int color, RectangleF
clipBounds, Matrix transformMatrix, TextOptions flags)
{
- var layout = CreateTextLayout(text, fontFamily, size,
layoutBounds, flags);
- DrawTextLayout(context, layout, layoutBounds.X,
layoutBounds.Y, color, clipBounds, transformMatrix, flags);
-
- layout.Dispose();
+ using (var layout = CreateTextLayout(text, fontFamily, size,
layoutBounds, flags))
+ DrawTextLayout(context, layout, layoutBounds.X,
layoutBounds.Y, color, clipBounds, transformMatrix, flags);
}

/// <summary>
@@ -225,13 +217,9 @@
/// <param name="flags">Text rendering flags.</param>
public void DrawTextLayout(DeviceContext context, TextLayout
textLayout, float originX, float originY, int color, TextOptions flags)
{
- bool needsGeometry = (flags & TextOptions.AnalyzeOnly) == 0 &&
(flags & TextOptions.CacheOnly) == 0;
- if (needsGeometry)
- geometry.Clear();
-
- AnalyzeTextLayout(context, textLayout, originX, originY,
color, flags, geometry);
- if (needsGeometry)
- unsafe { DrawGeometry(context, geometry, null, null,
flags); }
+ AnalyzeTextLayout(context, textLayout, originX, originY,
color, flags);
+ if ((flags & TextOptions.AnalyzeOnly) == 0 && (flags &
TextOptions.CacheOnly) == 0)
+ unsafe { DrawGeometry(context, null, null, flags); }
}

/// <summary>
@@ -247,13 +235,9 @@
/// <param name="flags">Text rendering flags.</param>
public void DrawTextLayout(DeviceContext context, TextLayout
textLayout, float originX, float originY, int color, RectangleF clipBounds,
Matrix transformMatrix, TextOptions flags)
{
- bool needsGeometry = (flags & TextOptions.AnalyzeOnly) == 0 &&
(flags & TextOptions.CacheOnly) == 0;
- if (needsGeometry)
- geometry.Clear();
-
- AnalyzeTextLayout(context, textLayout, originX, originY,
color, flags, geometry);
- if (needsGeometry)
- unsafe { DrawGeometry(context, geometry, &clipBounds,
&transformMatrix, flags); }
+ AnalyzeTextLayout(context, textLayout, originX, originY,
color, flags);
+ if ((flags & TextOptions.AnalyzeOnly) == 0 && (flags &
TextOptions.CacheOnly) == 0)
+ unsafe { DrawGeometry(context, &clipBounds,
&transformMatrix, flags); }
}

/// <summary>
@@ -316,35 +300,27 @@
return layout;
}

- void AnalyzeTextLayout(DeviceContext context, TextLayout layout,
float originX, float originY, int color, TextOptions flags, TextGeometry
geometry)
- {
- renderer.DrawTextLayout(layout, originX, originY, color,
flags, geometry);
+ void AnalyzeTextLayout(DeviceContext context, TextLayout layout,
float originX, float originY, int color, TextOptions flags)
+ {
+ renderer.DrawTextLayout(layout, originX, originY, color,
flags);

// flush the glyph atlas in case any new glyphs were added
if ((flags & TextOptions.NoFlush) == 0)
glyphAtlas.Flush(context);
}

- unsafe void DrawGeometry(DeviceContext context, TextGeometry
geometry, RectangleF* clipBounds, Matrix* transformMatrix, TextOptions
flags)
- {
- var vertexData = geometry.GetGlyphVertices();
- if (vertexData.Vertices.Length > 0 || (flags &
TextOptions.RestoreState) == 0)
- {
- // check if we can use geometry shaders
- if (featureLevel < FeatureLevel.Level_10_0 |
| !renderStates.HasGeometryShader)
- flags |= TextOptions.NoGeometryShader;
-
- using (new StateSaver(context, (flags &
TextOptions.RestoreState) != 0))
- {
- // set states and shaders
- if ((flags & TextOptions.StatePrepared) == 0)
- renderStates.SetStates(context, flags);
- if ((flags & TextOptions.ConstantsPrepared) == 0)
- renderStates.UpdateShaderConstants(context,
clipBounds, transformMatrix);
-
- // draw glyphs
- glyphDrawer.DrawVertices(context, glyphAtlas,
vertexData, flags);
- }
+ unsafe void DrawGeometry(DeviceContext context, RectangleF*
clipBounds, Matrix* transformMatrix, TextOptions flags)
+ {
+ using (new StateSaver(context, (flags &
TextOptions.RestoreState) != 0))
+ {
+ // set states and shaders
+ if ((flags & TextOptions.StatePrepared) == 0)
+ renderStates.SetStates(context, flags);
+ if ((flags & TextOptions.ConstantsPrepared) == 0)
+ renderStates.UpdateShaderConstants(context,
clipBounds, transformMatrix);
+
+ // draw glyphs
+ glyphDrawer.DrawVertices(context, glyphAtlas,
renderer.SortVertices(), flags);
}
}
}
=======================================
--- /branches/lite/SlimDX.Toolkit/SlimDX.Toolkit.csproj Fri Mar 23 16:09:34
2012
+++ /branches/lite/SlimDX.Toolkit/SlimDX.Toolkit.csproj Sat Mar 24 18:37:53
2012
@@ -52,19 +52,14 @@
<Compile Include="Drawing\TextureAtlas.cs" />
<Compile Include="Fonts\CreateOptions.cs" />
<Compile Include="Fonts\Font.cs" />
- <Compile Include="Fonts\Geometry\GlyphVertex.cs" />
- <Compile Include="Fonts\Geometry\TextGeometry.cs" />
- <Compile Include="Fonts\Geometry\TextRenderer.cs" />
- <Compile Include="Fonts\Glyphs\GlyphAtlas.cs" />
- <Compile Include="Fonts\Glyphs\GlyphData.cs" />
- <Compile Include="Fonts\Glyphs\GlyphProvider.cs" />
- <Compile Include="Fonts\Glyphs\GlyphSheet.cs" />
- <Compile Include="Fonts\Glyphs\HeightRange.cs" />
- <Compile Include="Fonts\Rendering\FontShaders.cs" />
- <Compile Include="Fonts\Rendering\NativeMethods.cs" />
- <Compile Include="Fonts\Rendering\RenderData.cs" />
- <Compile Include="Fonts\Rendering\RenderTargetWrapper.cs" />
- <Compile Include="Fonts\Rendering\VertexDrawer.cs" />
+ <Compile Include="Fonts\Internal\TextRenderer.cs" />
+ <Compile Include="Fonts\Internal\GlyphAtlas.cs" />
+ <Compile Include="Fonts\Internal\GlyphProvider.cs" />
+ <Compile Include="Fonts\Internal\FontShaders.cs" />
+ <Compile Include="Fonts\Internal\NativeMethods.cs" />
+ <Compile Include="Fonts\Internal\RenderData.cs" />
+ <Compile Include="Fonts\Internal\GlyphImageRenderer.cs" />
+ <Compile Include="Fonts\Internal\VertexDrawer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sprites\SpriteContextResources.cs" />
<Compile Include="Sprites\SpriteDeviceResources.cs" />
=======================================
--- /branches/lite/SlimDX.Toolkit/Sprites/SpriteBatch.cs Tue Mar 20
12:01:54 2012
+++ /branches/lite/SlimDX.Toolkit/Sprites/SpriteBatch.cs Sat Mar 24
18:37:53 2012
@@ -193,9 +193,9 @@
public void Dispose()
{
if (deviceResources != null)
- deviceResources.Dispose();
+ deviceResources.Release();
if (contextResources != null)
- contextResources.Dispose();
+ contextResources.Release();

deviceResources = null;
contextResources = null;
=======================================
--- /branches/lite/SlimDX.Toolkit/Utilities/SharedResourcePool.cs Sat Mar
17 21:28:36 2012
+++ /branches/lite/SlimDX.Toolkit/Utilities/SharedResourcePool.cs Sat Mar
24 18:37:53 2012
@@ -12,12 +12,17 @@
/// the resource will be freed.
/// </summary>
/// <typeparam name="T">The type of the resource being
shared.</typeparam>
- public interface ISharedResource<T> : IDisposable where T : IDisposable
+ public interface ISharedResource<T> where T : IDisposable
{
/// <summary>
/// The shared resource.
/// </summary>
T Resource { get; }
+
+ /// <summary>
+ /// Releases the reference to the resource, decrementing its ref
count.
+ /// </summary>
+ void Release();
}

/// <summary>
@@ -54,7 +59,7 @@
return Interlocked.Increment(ref RefCount);
}

- public void Dispose()
+ public void Release()
{
lock (Pool.syncBlock)
{
=======================================
--- /branches/lite/source/DataStream.cpp Sat Mar 17 11:15:48 2012
+++ /branches/lite/source/DataStream.cpp Sat Mar 24 18:37:53 2012
@@ -135,8 +135,6 @@

m_CanRead = canRead;
m_CanWrite = canWrite;
-
- GC::SuppressFinalize( this );
}

DataStream::~DataStream()
Reply all
Reply to author
Forward
0 new messages