Introduction The .NET Compact Framework is an excellent, if not the best, API for mobile devices. Its graphics engine is heavily throttled in order to increase rendering speed and reduce memory consumption. However, it seems far from meeting users' growing demands for a better graphics experience. Trying to get some of the advanced vector graphics rendering capabilities in the .NET Compact Framework can be a tedious task. Developers have two options:
1. Turn to native code. For example, the Pocket PC Game API might be a good choice. Its performance is impressive. For more information, see a very comprehensive article at: http://msdn.microsoft.com/mobility/samples/default.aspx?pull=/library/en-us/dnnetcomp/html/gmangame. asp . The problem is that the native code does not support vector graphics rendering and is not compatible with some devices. Additionally, it may not work with Pocket PC emulators. You can imagine how difficult it is to debug such a program.
2. Please wait for the next generation mobile graphics engine to come out. As far as I know, Windows CE 5 will contain a powerful Direct3D Mobile engine. This is good news for mobile game developers, but Direct3D is not suitable for two-dimensional graphics. It is too complex to be used in general applications.
What we need is a powerful and easy-to-use 2D graphics engine like GDI+. Therefore, I developed the XrossOne GDI+ project from scratch. It is written entirely in C# managed code and does not contain any native or unsafe code. After months of hard work, I can finally provide the downloadable original version at the beginning of this article.
Getting Started From the beginning of this project, it was always in my mind that the XrossOne GDI+ engine should be neutral across different handheld devices and platforms. As a result, it is compatible with Pocket PC, Windows CE, Smartphones, Windows .NET and Mono. You can copy the same runtime to a different target and it will still work fine.
The following table summarizes the overall architecture.
Layer namespaceXrossOne GDI+ API XrossOne.Drawing
Fixed-point based two-dimensional graphics engine XrossOne.DrawingFP
16.16 Fixed-point calculation engine XrossOne.FixedPoint
There are three layers in XrossOne GDI+. The lowest level is the "16.16 fixed-point computing engine". One of the main classes—MathFP—is adapted from the Beartronics J2ME library. Several functions have been optimized, including sqrt, atan, and PointFP.Distancecalculation. Under the namespace XrossOne.FixedPoint, there are three other classes: SingleFP, DoubleFP and MatrixFP. SingleFP is a Helper class for 16.16 fixed-point numbers. It provides convenience for converting between fixed-point types and standard types (int, float, string). MatrixFP is written for fixed-point 2D transformations. Because fixed-point calculations are less precise, some accuracy may be lost with cascaded transformations. For example, in most cases, two inversion operations cannot restore the original matrix. DoubleFP exists to complete the library, but is not yet used.
"Fixed-point based two-dimensional graphics engine" is the core of XrossOne GDI+. It implements many complex vector graphics algorithms, such as anti-aliased drawing, line cap/joint decoration, 2D transformations, gradient fills, alpha channel compositing, and more. Most of the advanced features in native GDI+ can be found here. However, you should only use it directly in a few cases because its fixed-point-based interface is not programmer-friendly, but don't worry too much about this situation. There is a well-encapsulated API available. You can find them in the XrossOne.Drawing namespace. The classes in XrossOne.Drawing are very similar to the classes in System.Drawing, except that each class has an "X" at the end. For example, the XrossOne.Drawing.PenX class is equivalent to System.Drawing.Pen. There is a little trick for converting GDI+ programs to XrossOne GDI+. In the using section, rename the XrossOne GDI+ classes to their equivalent classes. For example:
using Pen = XrossOne.Drawing.PenX;
using LinearGradientBrush = XrossOne.Drawing.LinearGradientBrushX;
using Matrix = XrossOne.Drawing.MatrixX;
Main Features Anti-Aliased Vector Graphics Drawing
All kinds of two-dimensional geometric shapes can be rendered through XrossOne Mobile GDI+, such as line segments, rectangles, polygons, ellipses, sectors, Bezier splines, cardinal splines, etc. However, sectors, Bezier splines, and radix splines are not available in the .NET Compact Framework. Additionally, all graphics are automatically anti-aliased when rendered. This helps achieve a super smooth quality. In the .NET Compact Framework, the width of the brush is fixed to 1 pixel. This limitation does not exist in XrossOne GDI+. Different sizes of brushes can be applied to the outlines of all shapes, as shown in Figure 1.
Figure 1. Anti-aliased vector graphics drawing
Code example 1
//Clear the background and reset the transform state
gx.Clear(Color.White);
gx.ResetTransform();
//Draw skew grid as the background
PenX pen = new PenX(Utils.FromArgb(0x40, Color.LightGray), 5);
for (int i = -Height; i < Width + Height; i+=20)
{
gx.DrawLine(pen, i, 0, i + Height, Height);
gx.DrawLine(pen, i, 0, i - Height, Height);
}
//Draw a DarkMagenta rectangle with a 10.5-pixel pen
Color c = Utils.FromArgb(0x80, Color.DarkMagenta);
pen = new PenX(c, 10.5f);
gx.DrawRectangle(pen, 50, 20, 150, 200);
//Fill a GreenYellow rectangle
c = Utils.FromArgb(0xA0, Color.GreenYellow);
BrushX brush = new SolidBrushX(c);
gx.FillRectangle(brush, 120, 50, 90, 150);
//Draw a BlueViolet ellipse with a 10.5-pixel pen
c = Utils.FromArgb(0x80, Color.BlueViolet);
pen = new PenX(c, 10.5f);
gx.DrawEllipse(pen, 50, 20, 150, 80);
//Fill a Red ellipse
c = Utils.FromArgb(0xA0, Color.Red);
brush = new SolidBrushX(c);
gx.FillEllipse(brush, 20, 50, 80, 150);
//Draw a HotPink pie from 156.5 degree to -280.9 degree
pen.Color = Utils.FromArgb(0xA0, Color.HotPink);
gx.DrawPie(pen, 3.6f, 120.3f, 200.8f, 130.1f, 156.5f, -280.9f);
//Draw Orange Bezier curves
c = Utils.FromArgb(0xA0, Color.Orange);
pen = new PenX(c, 16);
Point start = new Point(70, 100);
Point control1 = new Point(100, 10);
Point control2 = new Point(150, 50);
Point end1 = new Point(200, 200);
Point control3 = new Point(100, 150);
Point control4 = new Point(50, 200);
Point end2 = new Point(10, 150);
Point[] bezierPoints ={start, control1, control2, end1, control3, control4, end2};
pen.EndCap = LineCapX.Round;
gx.DrawBeziers(pen, bezierPoints);
//Refresh
Invalidate();
The vector graphics output of XrossOne GDI+ and native GDI+ is identical, with the exception of radix splines. My algorithm is taken from the article Smoothing Algorithm Using Bezier Curves by Jean-Yves Queinec. Therefore, you may find some differences between their outputs, as shown in Figure 2 below.
Figure 2. Output of DrawCurve/DrawClosedCurve
Although most of the vector graphics rendering functions have been implemented, there is still some work that needs to be done. Some functions (DrawString, DrawImage, DrawPath, etc.) will not be available until the next version.
gradient fill
There are five brushes in native GDI+—SolidBrush, LinearGradientBrush, PathGradientBrush, TextureBrush, and HatchBrush. However, in this version, only SolidBrush and LinearGradientBrush are available. XrossOne GDI+ supports RadialGradientBrush but not PathGradientBrush. Figure 5 below demonstrates a gradient fill.
Figure 5. Gradient fill
Code example 4
//Clear the background and reset the transform state
gx.Clear(Color.White);
gx.ResetTransform();
//Fill a rectangle with a black-white LinearGradientBrushX
Rectangle r = new Rectangle(20, 50, 300, 100);
Color c1 = Color.Black;
Color c2 = Color.White;
BrushX brush1 = new LinearGradientBrushX(r, c1, c2, 30F);
gx.FillRectangle(brush1, r);
//Fill a rectangle with a 7-color LinearGradientBrushX
r = new Rectangle(90, 100, 150, 100);
LinearGradientBrushX br = new LinearGradientBrushX(r,Color.Black,Color.Black, 60F);
ColorBlendX cb = new ColorBlendX();
cb.Positions=new float[7];
int i=0;
for(float f=0;f<=1;f+=1.0f/6)
cb.Positions[i++]=f;
cb.Colors=new Color[]
{Color.Red,Color.Orange,Color.Yellow,Color.Green,Color.Blue,Color.Indigo,Color.Violet};
br.InterpolationColors=cb;
gx.TranslateTransform(160, 10);
gx.RotateTransform(60F);
gx.FillRectangle(br, r);
//Fill a rectangle with a 7-color RadialGradientBrushX
rY += 50;
RadialGradientBrushX brush2 = new RadialGradientBrushX(r, Color.Black,Color.Black, 220F);
brush2.InterpolationColors = cb;
gx.RotateTransform(-45F);
gx.TranslateTransform(-200, -170);
gx.FillRectangle(brush2, r);
//Refresh
Invalidate();
Alpha channel compositing
The Color structure in the System.Drawing namespace is available in both the .NET Framework and the .NET Compact Framework. The difference is that the alpha component is disabled and the Hue-Saturation-Brightness (HSB) value is not available in the .NET Compact Framework. Fortunately, alpha channel compositing works perfectly with XrossOne GDI+ (as you may have inferred from the previous graphics example).
performance 3.505 ms 1.602 ms 118.8 % DrawCurve 4.006 ms 1.402 ms 185.7% DrawPie 6.810 ms 2.003 ms 240.0% TranslateTransform 10.615 ms 3.405 ms 211.7% ScaleTransform 4.106 ms 0.801 ms 412.6% RotateTransform 7.811 ms 1.803 ms 333.2% LinearGradient ( 1) 9.013 ms 2.103 ms 328.6% LinearGradient (2) 8.012 ms 1.803 ms 344.4 %
It's true that handheld PC CPUs are often much less powerful than standard PC CPUs. Heavy calculations can make handheld devices less responsive, which can become frustrating for users. In other words, performance is critical for handheld device software. Therefore, before using XrossOne Mobile GDI+ in a major situation, you may want to analyze its overall performance. Because most of the equivalent functions in GDI+ for the .NET Compact Framework are not available, the benchmarks were conducted between XrossOne Mobile GDI+ and GDI+ for the .NET Framework. Tests were performed in the following categories: vector graphics rendering, 2D transformations, and gradient fills. The test scenarios were executed under the same conditions. You can find the benchmark programs in the download package, and you can quickly view their graphical output at http://www.xrossone.com/projects.php?menu=4.
XrossOne Mobile GDI+ is written entirely in C# managed code, and its overall performance is acceptable (see table below), although 2D transforms and gradient fills will need further optimization in future versions.
Solution 66.7 % DrawBezier