# Advanced GDI Functions Based on NEWGAL - [New Region Implementation](#new-region-implementation) - [Raster Operations](#raster-operations) - [Memory `DC` and `BitBlt`](#memory-dc-and-bitblt) - [Enhanced `BITMAP` Operations](#enhanced-bitmap-operations) - [New `GDI` functions](#new-gdi-functions) - [Advanced `GDI` functions](#advanced-gdi-functions) + [Image Scaling Functions](#image-scaling-functions) + [Image Rotation Functions](#image-rotation-functions) + [Rounded Corners Rectangle](#rounded-corners-rectangle) - [Curve Generators](#curve-generators) + [Line Clipper and Line Generator](#line-clipper-and-line-generator) + [Circle Generator](#circle-generator) + [Ellipse Generator](#ellipse-generator) + [Arc Generator](#arc-generator) + [Vertical Monotonous Polygon Generator](#vertical-monotonous-polygon-generator) + [General Polygon Generator](#general-polygon-generator) + [Flood Filling Generator](#flood-filling-generator) + [Using Curve Generator](#using-curve-generator) - [Plotting Complex Curve](#plotting-complex-curve) - [Filling Enclosed Curve](#filling-enclosed-curve) - [Building Complex Region](#building-complex-region) - [Visiting Frame Buffer Directly](#visiting-frame-buffer-directly) - [Advanced Two-Dimension `GDI` Functions](#advanced-two-dimension-gdi-functions) + [Pen and Its Properties](#pen-and-its-properties) + [Brush and Its Properties](#brush-and-its-properties) + [Advanced Two-Dimension Drawing Functions](#advanced-two-dimension-drawing-functions) + [Using Advanced Two-Dimension `GDI` Functions](#using-advanced-two-dimension-gdi-functions) - [Support for Slave Screens](#support-for-slave-screens) + [Creating Slave Screen](#creating-slave-screen) + [Destroying Slave Screen](#destroying-slave-screen) It is mentioned in Chapter 13 that MiniGUI 1.1.0 has greatly improved `GAL` and `GDI` by rewriting almost all code. Those new interfaces and functions strongly enhance the graphics capability of MiniGUI. In this chapter we will introduce the related concepts and interfaces of new `GDI` interface in detail. ## New Region Implementation New `GDI` uses new region algorithm, which is popularly used in X Window and other GUI systems. This region is called x-y-banned region, featured as follow: - Region is constituted by non-null rectangles that is not intersected each other. - Region can be divided into several non-intersected horizontal strip, each of which has the rectangles with same width and top-aligned; In other words, all rectangles have the same y coordinates on the upper-left corner. - The rectangles rank from left to right at the x direction, and then form top to bottom at y direction. `GDI` can use the special property of x-y-banned region to optimize the drawing. Those drawing functions that will be added into the future version will use this property to optimize plotting output. New `GDI` adds the following interfaces, which can be used to do operations between regions (`minigui/gdi.h`): ```cpp BOOL GUIAPI PtInRegion (PCLIPRGN region, int x, int y); BOOL GUIAPI RectInRegion (PCLIPRGN region, const RECT* rect); void GUIAPI OffsetRegionEx (PCLIPRGN region, const RECT *rcClient, const RECT *rcScroll, int x, int y); void GUIAPI OffsetRegion (PCLIPRGN region, int x, int y); BOOL GUIAPI IntersectRegion (CLIPRGN *dst, const CLIPRGN *src1, const CLIPRGN *src2); BOOL GUIAPI UnionRegion (PCLIPRGN dst, const CLIPRGN* src1, const CLIPRGN* src2); BOOL GUIAPI SubtractRegion (CLIPRGN* rgnD, const CLIPRGN* rgnM, const CLIPRGN* rgnS); BOOL GUIAPI XorRegion (CLIPRGN *dst, const CLIPRGN *src1, const CLIPRGN *src2); ``` - `PtInRegion` checks if the given point locates in the given region. - `RectInRegion` checks if the given rectangle intersects with the given region. - `OffsetRegionEx` offsets the clip region located in the intersection of two given rectangles, one is the rectangle the original clip region belongs to, and the other is the one which offset region belongs to. And then form a clip region which belong to both the offset part of the original region and the intersection of the two rectangles. - `OffsetRegion` just offsets the given region. - `IntersectRegion` can be used to calculate the intersection of two given region. - `UnionRegion` can merge two different regions. The merged region is still a region of x-y-banned. - `SubstractRegion` subtracts one region from another. - `XorRegion` is used to perform the `XOR` (Exclusive `OR`) operation between two regions. The result equals to the intersection between the result A that `src1` subtracts `src2` and the result B that `src2` subtracts `src1`. Apart from the region operation functions above, MiniGUI also provides those `GDI` functions that created from the closed curve such as polygon and ellipse. These functions can limit `GDI` output within the specially closed curve. These functions will be discussed in the following sections. ## Raster Operations Raster operation specifies the operation between the target pixel and the pixel existed on the screen while drawing. The most popular one is alpha blending. Here the raster operation refers to binary bit operation, including `AND`, `OR`, `XOR`, and directly overwrite (SET). Application can use `SetRasterOperation` function and `GetRasterOperation` function to set or get current raster operation. The prototypes of these two functions are as follow (`minigui/gdi.h`): ```cpp #define ROP_SET 0 #define ROP_AND 1 #define ROP_OR 2 #define ROP_XOR 3 int GUIAPI GetRasterOperation (HDC hdc); int GUIAPI SetRasterOperation (HDC hdc, int rop); ``` In the function, `rop` is the raster operation mode. The optional parameters are `ROP_SET` (directly set), `ROP_AND` (do bit-AND with the pixels on the screen), `ROP_OR` (do bit-OR with the pixels on the screen) and `POP_XOR` (do exclusive-OR with the pixels on the screen). After setting new raster operation, the subsequent graphics output will be affected by it. Those drawing functions include `SetPixel`, `LineTo`, Circle, Rectangle, `FillCircle`, and `FillBox`. Please notice, new `GDI` function has a new rectangle filling function - `FillBox`. `FillBox` function is not influenced by the current raster operation, just because `FillBox` realize Rectangle filling by using Hardware acceleration function, and its filling speed is very high. ## Memory `DC` and `BitBlt` New `GDI` function boosts up the memory `DC` operation function. `GDI` function will call `GAL-related` interface while setting memory `DC` as it will fully use the hardware acceleration of video adapter to quickly move or copy the bit blocks between different regions, including transparency processing and alpha blending. Application can create a memory `DC` with the property that each point has different alpha value. Also, application can create the alpha value (alpha channel of the `DC`) of all pixels of memory `DC` by using `SetMemDCAlpha`, then use `BitBlt` and `StretchBlt` to transfer the bits between `DCs`. Application also can set the transparent pixel of a source `DC`, so as to leap over such pixel while performing `BitBlt`. `GDI` functions regarding memory `DC` are as follow (`minigui/gdi.h`): ```cpp #define MEMDC_FLAG_NONE 0x00000000 /* None. */ #define MEMDC_FLAG_SWSURFACE 0x00000000 /* DC is in system memory */ #define MEMDC_FLAG_HWSURFACE 0x00000001 /* DC is in video memory */ #define MEMDC_FLAG_SRCCOLORKEY 0x00001000 /* Blit uses a source color key */ #define MEMDC_FLAG_SRCALPHA 0x00010000 /* Blit uses source alpha blending */ #define MEMDC_FLAG_RLEACCEL 0x00004000 /* Surface is RLE encoded */ HDC GUIAPI CreateCompatibleDC (HDC hdc); HDC GUIAPI CreateMemDC (int width, int height, int depth, DWORD flags, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); BOOL GUIAPI ConvertMemDC (HDC mem_dc, HDC ref_dc, DWORD flags); BOOL GUIAPI SetMemDCAlpha (HDC mem_dc, DWORD flags, Uint8 alpha); BOOL GUIAPI SetMemDCColorKey (HDC mem_dc, DWORD flags, Uint32 color_key); HDC GUIAPI CreateMemDCFromBitmap (HDC hdc, BITMAP *bmp); HDC GUIAPI CreateMemDCFromMyBitmap (const MYBITMAP *my_bmp, RGB *pal); void GUIAPI DeleteMemDC (HDC mem_dc); ``` `CreateCompatibleDC` creates a memory `DC` compatible with given `DC`. Compatibility means that the pixel format, width and height of new created memory `DC` are same with the given `DC`. Memory `DC` based on this format can be quickly blited to the compatible `DC`. Now we further explain the pixel format. Pixel format includes the depth of color (that is, the number of bits per pixel), palette, or the format of four components of `RGBA` (red, green, blue, and alpha). The parameter alpha can be seen as the transparency degree of one pixel point, 0 means 100% transparent, 255 means completely opaque. If the degree of color below 8, `GAL` will create a default palette and you can call the function `SetPalette` to modify the palette. If the degree is higher than 8, MiniGUI will respectively appoint the bits taken up by the `RGBA` parameters of the given pixel. Compatible memory `DC` has the same color degree with the given `DC`, and has the same palette or `RGBA` parameter combination format. Calling function `CreateMemDC` can specify the height, width, color depth, and necessary `RGBA` components combination format of the new created memory `DC`. MiniGUI use bit mask taken up by each pixel to represent the combination format of `RGBA` components. For example, to create a 16-bit memory `DC` including per-pixel alpha value, you can use four 4-bit to assign 16-bit pixel, thus the mask of the four components of `RBGA` will respectively be: 0x0000F000, 0x00000F00, 0x000000F0, and 0x0000000F. `ConvertMemDC` is used to convert a specified memory `DC` according to the pixel format of given referencing `DC`. This conversion makes the result `DC` has the same pixel format with referencing `DC`. Thus, the converted `DC` can be quickly blited to the compatible `DC`. `SetMemDCAlpha` is used to set or delete the alpha channel value of whole memory `DC`. We can use `MEMDC_FLAG_RLEACCEL` to specify the memory `DC` adopt or delete the `RLE` encoding format. Alpha channel value will function on all pixels of the `DC`. `SetMemDCColorKey` is used to set or delete the color key of whole memory `DC` object, that is, the transparent pixel value. We can also use `MEMDC_FLAG_RLEACCEL` to specify memory `DC` adopt or delete the `RLE` encoding format. `CreateMemDCFromBitmap` can create a memory `DC` compatible with given `DC` that point to device relative Bitmap, and it can be quickly copy and exchange to display from bitmap. `CreateMemDCFromMyBitmap` create a memory `DC` which points to a device independent bitmap. Similar to other `DCs`, you can also call `GDI` drawing function to perform any drawing output operation in memory `DC` and then blit it to other `DC`. Code in List 1 comes from `gdidemo.c` program of `mg-samples`, which demonstrates how to use memory `DC` to realize transparent and alpha blending blitting operation between `DCs`. List 1 The enhanced memory `DC` operations ```cpp /* Alpha operation point by point*/ mem_dc = CreateMemDC (400, 100, 16, MEMDC_FLAG_HWSURFACE | MEMDC_FLAG_SRCALPHA, 0x0000F000, 0x00000F00, 0x000000F0, 0x0000000F); /* Set an opaque brush and fill a rectangle */ SetBrushColor (mem_dc, RGBA2Pixel (mem_dc, 0xFF, 0xFF, 0x00, 0xFF)); FillBox (mem_dc, 0, 0, 200, 50); /* Set a brush transparent by 25% and fill a rectangle */ SetBrushColor (mem_dc, RGBA2Pixel (mem_dc, 0xFF, 0xFF, 0x00, 0x40)); FillBox (mem_dc, 200, 0, 200, 50); /* Set a brush half transparent and fill a rectangle */ SetBrushColor (mem_dc, RGBA2Pixel (mem_dc, 0xFF, 0xFF, 0x00, 0x80)); FillBox (mem_dc, 0, 50, 200, 50); /* Set a brush transparent by 75% and fill a rectangle */ SetBrushColor (mem_dc, RGBA2Pixel (mem_dc, 0xFF, 0xFF, 0x00, 0xC0)); FillBox (mem_dc, 200, 50, 200, 50); SetBkMode (mem_dc, BM_TRANSPARENT); /* Output text with half transparent pixel point */ SetTextColor (mem_dc, RGBA2Pixel (mem_dc, 0x00, 0x00, 0x00, 0x80)); TabbedTextOut (mem_dc, 0, 0, "Memory DC with alpha.\n" "The source DC have alpha per-pixel."); /* Blit into window DC */ start_tick = GetTickCount (); count = 100; while (count--) { BitBlt (mem_dc, 0, 0, 400, 100, hdc, rand () % 800, rand () % 800); } end_tick = GetTickCount (); TellSpeed (hwnd, start_tick, end_tick, "Alpha Blit", 100); /* Delete memory DC */ DeleteMemDC (mem_dc); /* A memory DC with Alpha channel: 32 bits, RGB takes 8 bits respectively, no Alpha component */ mem_dc = CreateMemDC (400, 100, 32, MEMDC_FLAG_HWSURFACE | MEMDC_FLAG_SRCALPHA | MEMDC_FLAG_SRCCOLORKEY, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000); /* Output the filled rectangle and text to memory DC */ SetBrushColor (mem_dc, RGB2Pixel (mem_dc, 0xFF, 0xFF, 0x00)); FillBox (mem_dc, 0, 0, 400, 100); SetBkMode (mem_dc, BM_TRANSPARENT); SetTextColor (mem_dc, RGB2Pixel (mem_dc, 0x00, 0x00, 0xFF)); TabbedTextOut (mem_dc, 0, 0, "Memory DC with alpha.\n" "The source DC have alpha per-surface."); /* Blit into window DC */ start_tick = GetTickCount (); count = 100; while (count--) { /* Set the Alpha channel of memory DC */ SetMemDCAlpha (mem_dc, MEMDC_FLAG_SRCALPHA | MEMDC_FLAG_RLEACCEL, rand () % 256); BitBlt (mem_dc, 0, 0, 400, 100, hdc, rand () % 800, rand () % 800); } end_tick = GetTickCount (); TellSpeed (hwnd, start_tick, end_tick, "Alpha Blit", 100); /* Fill rectangle area, and output text */ FillBox (mem_dc, 0, 0, 400, 100); SetBrushColor (mem_dc, RGB2Pixel (mem_dc, 0xFF, 0x00, 0xFF)); TabbedTextOut (mem_dc, 0, 0, "Memory DC with alpha and colorkey.\n" "The source DC have alpha per-surface.\n" "And the source DC have a colorkey, \n" "and RLE accelerated."); /* Set the transparent pixel value of memory DC */ SetMemDCColorKey (mem_dc, MEMDC_FLAG_SRCCOLORKEY | MEMDC_FLAG_RLEACCEL, RGB2Pixel (mem_dc, 0xFF, 0xFF, 0x00)); /* Blit into window DC */ start_tick = GetTickCount (); count = 100; while (count--) { BitBlt (mem_dc, 0, 0, 400, 100, hdc, rand () % 800, rand () % 800); CHECK_MSG; } end_tick = GetTickCount (); TellSpeed (hwnd, start_tick, end_tick, "Alpha and colorkey Blit", 100); /* Delete the object of memory DC */ DeleteMemDC (mem_dc); ``` ## Enhanced `BITMAP` Operations New `GDI` function enhances the `BITMAP` structure and adds support to transparent and alpha channel as well as. By setting such memberships as `bmType`, `bmAlpha`, and `bmColorkey` of a `BITMAP` object, you can get certain properties. Then you can use function `FillBoxWithBitmap/Part` to draw the `BITMAP` object to certain `DC`. You can regard the `BITMAP` object as the memory `DC` created in system memory, but you cannot perform drawing output to the `BITMAP` object. Code in List 2 loads a bitmap object from an image file, set transparency and alpha channel, and finally use function `FillBoxWithBitmap` to output to a `DC`. This program comes from the demo program `gdidemo.c` of `mg-samples`. List 2 The enhanced `BITMAP` operations ```cpp int tox = 800, toy = 800; int count; BITMAP bitmap; unsigned int start_tick, end_tick; if (LoadBitmap (hdc, &bitmap, "res/icon.bmp")) return; bitmap.bmType = BMP_TYPE_ALPHACHANNEL; /* Alpha mixing of the bitmap */ start_tick = GetTickCount (); count = 1000; while (count--) { tox = rand() % 800; toy = rand() % 800; /* Set random Alpha channel value */ bitmap.bmAlpha = rand() % 256; /* Display into window DC */ FillBoxWithBitmap (hdc, tox, toy, 0, 0, &bitmap); } end_tick = GetTickCount (); TellSpeed (hwnd, start_tick, end_tick, "Alpha Blended Bitmap", 1000); bitmap.bmType = BMP_TYPE_ALPHACHANNEL | BMP_TYPE_COLORKEY; /* Get the first pixel value, and set it as transparent pixel value */ bitmap.bmColorKey = GetPixelInBitmap (&bitmap, 0, 0); /* Transparent and Alpha mixing */ start_tick = GetTickCount (); count = 1000; while (count--) { tox = rand() % 800; toy = rand() % 800; /* Set random Alpha channel value */ bitmap.bmAlpha = rand() % 256; /* Display into window DC */ FillBoxWithBitmap (hdc, tox, toy, 0, 0, &bitmap); } end_tick = GetTickCount (); TellSpeed (hwnd, start_tick, end_tick, "Alpha Blended Transparent Bitmap", 1000); UnloadBitmap (&bitmap); ``` You can also convert a certain `BITMAP` object to memory `DC` object by using function `CreateMemDCFromBitmap`. The prototype of this function is as follows (`minigui/gdi.h`): ```cpp HDC GUIAPI CreateMemDCFromBitmap (HDC hdc, BITMAP* bmp); ``` The memory `DC` created from a `BITMAP` object directly uses the memory to which `bmBits` of the `BITMAP` object points. The memory lies in system memory, but not video memory. New `GDI` also enhances the `BITMAP-related` `MYBITMAP` structure. `MYBITMAP` can be seen as a bitmap structure that is not dependent to the device. You can also convert one `MYBITMAP` object to a memory `DC` by using function `CreateMemDCFromMyBitmap`. The prototype of this function is as follows (`minigui/gdi.h`): ```cpp HDC GUIAPI CreateMemDCFromMyBitmap (HDC hdc, MYBITMAP* mybmp); ``` Most `GAL` engines are unable to provide hardware acceleration for blitting operation which transfers pixels from system memory to video memory, therefore, the `FillBoxWithBitmap` function, the `BITMAP` object or the memory `DC` created by `MYBITMAP` object are unable to be quickly blited to other `DC` through hardware acceleration. The support for such acceleration can be achieved by pre-created memory `DC` in video memory. ## New `GDI` functions Apart from raster operation, MiniGUI also adds some useful `GDI` functions, including `FillBox`, `FillCircle`, and so on. The new `GDI` functions are: ```cpp void GUIAPI FillBox (HDC hdc, int x, int y, int w, int h); void GUIAPI FillCircle (HDC hdc, int sx, int sy, int r); BOOL GUIAPI ScaleBitmap (BITMAP* dst, const BITMAP* src); BOOL GUIAPI GetBitmapFromDC (HDC hdc, int x, int y, int w, int h, BITMAP* bmp); gal_pixel GUIAPI GetPixelInBitmap (const BITMAP* bmp, int x, int y); BOOL GUIAPI SetPixelInBitmap (const BITMAP* bmp, int x, int y, gal_pixel pixel); ``` - `FillBox` fills specified rectangle. - `FillCircle` fills specified circle, affected by raster operation. - `ScaleBitmap` scales a `BITMAP` object - `GetBitmapFromDC` copies pixels which the scope is in a specified rectangle to a `BITMAP` object. - `GetPixelInBitmap` gets pixel value of a given position in a `BITMAP` object. - `SetPixelInBitmap` sets pixel value of a given position in a `BITMAP` object. ## Advanced `GDI` functions ### Image Scaling Functions The following functions can be used to paint and scale an image simultaneously. ```cpp int GUIAPI StretchPaintImageFromFile (HDC hdc, int x, int y, int w, int h, const char* spFileName); int GUIAPI StretchPaintImageFromMem (HDC hdc, int x, int y, int w, int h, const void* mem, int size, const char* ext); int GUIAPI StretchPaintImageEx (HDC hdc, int x, int y, int w, int h, MG_RWops* area, const char* ext); ``` - `StretchPaintImageFromFile` stretches and paints an image from file. Parameter `hdc` is device context. Parameter x and y are painting position on device. Parameter w is the width of the stretched bitmap. Parameter h is the height of the stretched bitmap. Parameter `spFileName` is the file name. - `StretchPaintImageFromMem` stretches an image from memory. Parameter `hdc` is device context. Parameter x and y are painting position on device. Parameter w is the width of the stretched bitmap. Parameter h is the height of the stretched bitmap. Parameter `mem` points to memory containing image data and parameter size is the size of the image data. Parameter ext is the type of bitmap. - `StretchPaintImageEx` paints and stretches an image from data source onto device directly. Parameter `hdc` is device context. Parameter x and y are painting position on device. Parameter w is the width of the stretched bitmap. Parameter h is the height of the stretched bitmap. Parameter area points to data source and parameter ext is the extension the type of bitmap. ### Image Rotation Functions The following functions can be used to paint an `BITMAP` object and rotate it. ```cpp void GUIAPI PivotScaledBitmapFlip (HDC hdc, const BITMAP *bmp, fixed x, fixed y, fixed cx, fixed cy, int angle, fixed scale_x, fixed scale_y, BOOL h_flip, BOOL v_flip); void GUIAPI RotateBitmap (HDC hdc, const BITMAP* bmp, int lx, int ty, int angle); void GUIAPI PivotBitmap (HDC hdc, const BITMAP *bmp, int x, int y, int cx, int cy, int angle); void GUIAPI RotateScaledBitmap (HDC hdc, const BITMAP *bmp, int lx, int ty, int angle, int w, int h); void GUIAPI RotateBitmapVFlip (HDC hdc, const BITMAP *bmp, int lx, int ty, int angle); void GUIAPI RotateBitmapHFlip (HDC hdc, const BITMAP *bmp, int lx, int ty, int angle); void GUIAPI RotateScaledBitmapVFlip (HDC hdc, const BITMAP *bmp, int lx, int ty, int angle, int w, int h); void GUIAPI RotateScaledBitmapHFlip (HDC hdc, const BITMAP *bmp, int lx, int ty, int angle, int w, int h); ``` - `PivotScaledBitmapFlip` rotates, stretches, shrinks, or flips a bitmap object. The unit of rotation is 1/64 degree in this function. Parameter hdc is device context. Parameter bmp is a `BITMAP` object pointer. Parameter x and y are rotation center on `DC`. Parameter (cx, cy) is the rotation center on the bitmap. The data type of x, y, cx, cy are fixed-point values. Parameter angle is the degree of rotation. Parameter `scale_x` and `scale_y` are proportion of scaling. Parameter `h_flip` and `v_flip` are flags for flipping horizontally or flipping vertically. - `RotateBitmap` rotates a bitmap object surrounded its center. Parameter hdc is the graphic device context handle. Parameter bmp is the pointer to a `BITMAP` object. Parameter lx and ly are upper-left coordinate of bitmap on `DC`. Parameter angle is the degree of rotation. The unit of rotation is 1/64 degree. - `PivotBitmap` aligns the point in the bitmap given by parameter (cx, cy) to parameter (x, y) in device context. Parameter hdc is the device context. Parameter bmp is the pointer to a `BITMAP` object. Parameter x and y are rotation center on `DC`. Parameter (cx, cy) is the rotation center on the bitmap. Parameter angle is the degree of rotation. The unit of rotation is 1/64 degree. - `RotateScaledBitmap` stretches or shrinks a bitmap object at the same as rotating it. Parameter hdc is the device context. Parameter bmp is the pointer to a `BITMAP` object. Parameter lx and ly are upper-left coordinates of bitmap on `DC`. Parameter angle is the degree of rotation. The unit of rotation is 1/64 degree. Parameter w and h are width and height of the stretched bitmap. - `RotateBitmapVFlip` flips vertically and rotates a bitmap object. See also `RotateBitmap`. - `RotateBitmapHFlip` flips horizontally and rotates a bitmap object. See also `RotateBitmap`. - `RotateScaledBitmapVFlip` flips vertically, rotates, stretch or shrinks a bitmap object. This function is similar to `RotateScaledBitmap` expect that it flips the bitmap vertically first. - `RotateScaledBitmapHFlip` flips horizontally, rotates, stretches or shrinks a bitmap object. For the means of parameters, please refer to `RotateScaledBitmap`. ### Rounded Corners Rectangle The follow function draws a rounded corners rectangle ```cpp BOOL GUIAPI RoundRect (HDC hdc, int x0, int y0, int x1, int y1, int rw, int rh); ``` Here, hdc is the graphic device context handle. x0 and y0 are coordinates of upper-left corner of the rectangle; x1 and y1 are coordinates of lower-right of the rectangle; rw and rh are the x-radius and y-radius of the rounded corners respectively. ## Curve Generators A general graphics system usually provides the user with the drawing functions to plot line and complicated curve, such as ellipse, and spline. Users can use this function to plot, but unable to do other jobs by using the existed curve-generating algorithms. In the development of new `GDI` interface, we use a special design pattern to implement drawing of curve and filling of closed curve. This way is very flexible and provides you a chance of directly using system internal algorithm: - System defines several functions used to create line and curve. We call these functions curve generators. - You need to define a callback and pass this function address to curve generator before calling a generator. The curve generator will call this callback while generating a point on the curve or a horizontal line of closed curve. - You can finish some operations based on new point or new horizontal line. For the MiniGUI drawing function, that means drawing the point or the line. - As callback is frequently called on during the generator operating process, system allows you to pass a pointer to represent context while calling the curve generator. The generator will pass this pointer to your callback. We will describe curve and filling generator provided by MiniGUI in the following sections. ### Line Clipper and Line Generator The prototype of the line clipper and generator is as follows: ```cpp /* Line clipper */ BOOL GUIAPI LineClipper (const RECT* cliprc, int *_x0, int *_y0, int *_x1, int *_y1); /* Line generators */ typedef void (* CB_LINE) (void* context, int stepx, int stepy); void GUIAPI LineGenerator (void* context, int x1, int y1, int x2, int y2, CB_LINE cb); ``` `LineClipper` is not a generator, which is used to clip the given line into a rectangle. The argument `cliprc` is the given rectangle, while `_x0`, `_y0`, `_x1`, and `_y1` present the two end-points of the line that will be clipped into `cliprc` and then return to the end-points of the clipped line. MiniGUI internally uses Cohen-Sutherland algorithm to clip a line. `LineGenerator` is the line generator using Breshenham algorithm. The generator starts from the beginning point of given line, every time when it generates a point it will call the callback function and pass context as well as the step forward value or amount of difference between new point and the previous one. For example, passing `stepx = 1`, `stepy = 0` indicate that the new point is one step forward then the previous point at x coordinate, while y coordinate keeps the same. The callback function can realize the optimization at certain degree on the basis of step forward value. ### Circle Generator The prototypes of MiniGUI-defined circle generator are as follow: ```cpp /* Circle generator */ typedef void (* CB_CIRCLE) (void* context, int x1, int x2, int y); void GUIAPI CircleGenerator (void* context, int sx, int sy, int r, CB_CIRCLE cb); ``` You should firstly specify the coordinates of center of the circle and the radius, and then pass information of context and the callback function. Every time when it generates a point, the generator will call the callback function once, at the same time it passes three values: x1, x2, and y. These three values actually indicate two points on the circle: (x1, y) and (x2, y). Because of the symmetry property of circle, the generator can get all points on the circle by calculating only 1/4 of points in the circle. ### Ellipse Generator Similar to circle generator, the prototypes of ellipse generator are as follow: ```cpp /* Ellipse generator */ typedef void (* CB_ELLIPSE) (void* context, int x1, int x2, int y); void GUIAPI EllipseGenerator (void* context, int sx, int sy, int rx, int ry, CB_ELLIPSE cb); ``` You should firstly specify the coordinates of center of ellipse and the radius of x coordinate and y coordinate, and then pass the context and the callback function. Every time when it generates a point, the generator will call the callback function once, at the same time it passes three values: x1, x2, and y. These three values actually indicate two points in the ellipse: (x1, y) and (x2, y). Because of the symmetry property of ellipse, the generator can get all points in the ellipse by calculating only half of points of the ellipse. ### Arc Generator The MiniGUI-defined arc generator can be seen as follows: ```cpp /* Arc generator */ typedef void (* CB_ARC) (void* context, int x, int y); void GUIAPI CircleArcGenerator (void* context, int sx, int sy, int r, int ang1, int ang2, CB_ARC cb); ``` You should firstly specify the center of the arc, the radius, the starting angle and the end angle. It is necessary to note that the unit of the starting angle and end angle is integers in 1/64 degree, not float-point numbers. Then you pass the callback function. Every time when it generates a point on the arc, the function will call the callback function and pass the coordinates value (x, y) of a new point on the arc. ### Vertical Monotonous Polygon Generator Generally speaking, polygons include protruding polygons and concave polygons. Here the vertical monotonous polygon is a special polygon produced for optimizing polygon algorithm in the computer graphics. The definition of this kind of polygon is: all the horizontal lines of the computer screen and the side of polygon can only have one or two points of intersection. Figure 1 gives examples of protruding polygon, concave polygon, and vertical monotonous polygon. ![alt](figures/15.1_T.jpeg) Figure 1 Polygons It is necessary to note that a protruding polygon must be vertical monotonous polygon, but a vertical monotonous polygon can be concave polygon. Obviously, normal polygon filling algorithms need to determine the number of intersection point between polygon and the screen scan line while vertical monotonous polygons not. Therefore, the speed of polygon filling can be greatly increased. The prototypes of MiniGUI-defined vertical monotonous polygon related functions are as follow: ```cpp /* To determine whether the specified Polygon is Monotone Vertical Polygon */ BOOL GUIAPI PolygonIsMonotoneVertical (const POINT* pts, int vertices); /* Monotone vertical polygon generator */ typedef void (* CB_POLYGON) (void* context, int x1, int x2, int y); BOOL GUIAPI MonotoneVerticalPolygonGenerator (void* context, const POINT* pts, int vertices, CB_POLYGON cb); ``` `PolygonIsMonotoneVertical` is used to determine if a given polygon is vertical monotonous polygon while `MonotoneVerticalPolygonGenerator` is the generator of vertical monotonous polygon. In MiniGUI, the vertices of the polygon represent a polygon. The argument `pts` represents the vertices array while vertices represents the number of the vertices. What generator generates actually are the end-points `(x1, y)` and `(x2, y)` of each horizontal line to filling the polygon. ### General Polygon Generator MiniGUI also provides the general polygon generator, which can be used to process protruding polygons and concave polygons. The prototypes are as follow: ```cpp /* General polygon generator */ typedef void (* CB_POLYGON) (void* context, int x1, int x2, int y); BOOL GUIAPI PolygonGenerator (void* context, const POINT* pts, int vertices, CB_POLYGON cb); ``` Similar to vertical monotonous polygon generator, what this function generates are horizontal scan lines for filling the polygon: x1 is the beginning x coordinates of the horizontal line; x2 is the end x coordinate; y is the y coordinate of horizontal line. ### Flood Filling Generator with the one at the start position (Like water spreading, so called flood filling). Between the starting point and the ending point, it fills certain region according to a given color. During this process, we need two callback functions, one of which is used to determine if the encountered point is the same with the starting one; another callback function is used to generate the horizontal scan line of the filling region. When plotting what this function compares is pixel, but actually it can be used to compare any other values so as to finish the special spreading actions. MiniGUI defines flood-filling generator as follows: ```cpp /* General Flood Filling generator */ typedef BOOL (* CB_EQUAL_PIXEL) (void* context, int x, int y); typedef void (* CB_FLOOD_FILL) (void* context, int x1, int x2, int y); BOOL GUIAPI FloodFillGenerator (void* context, const RECT* src_rc, int x, int y, CB_EQUAL_PIXEL cb_equal_pixel, CB_FLOOD_FILL cb_flood_fill); ``` The function `cb_equal_pixel` is called to determine if the target point is same with the staring point. The pixel of starting point can be transferred by context. The function `cb_flood_fill` is used to fill in a scan line. It passes the end-points of the scan line, that is, (x1, y) and (x2, y). ### Using Curve Generator The way of using curve and filling generator is very simple. We firstly see how MiniGUI uses the curve and filling generator in its internal in order to deeply understand them. The program paragraph comes from `FloodFill` function of MiniGUI (`src/newgdi/flood.c`): ```cpp static void _flood_fill_draw_hline (void* context, int x1, int x2, int y) { PDC pdc = (PDC)context; RECT rcOutput = {MIN (x1, x2), y, MAX (x1, x2) + 1, y + 1}; ENTER_DRAWING (pdc, rcOutput); _dc_draw_hline_clip (context, x1, x2, y); LEAVE_DRAWING (pdc, rcOutput); } static BOOL equal_pixel (void* context, int x, int y) { gal_pixel pixel = _dc_get_pixel_cursor ((PDC)context, x, y); return ((PDC)context)->skip_pixel == pixel; } /* FloodFill * Fills an enclosed area (starting at point x, y). */ BOOL GUIAPI FloodFill (HDC hdc, int x, int y) { PDC pdc; BOOL ret = TRUE; if (!(pdc = check_ecrgn (hdc))) return TRUE; /* hide cursor tempororily */ ShowCursor (FALSE); coor_LP2SP (pdc, &x, &y); pdc->cur_pixel = pdc->brushcolor; pdc->cur_ban = NULL; pdc->skip_pixel = _dc_get_pixel_cursor (pdc, x, y); /* does the start point have a equal value? */ if (pdc->skip_pixel == pdc->brushcolor) goto equal_pixel; ret = FloodFillGenerator (pdc, &pdc->DevRC, x, y, equal_pixel, _flood_fill_draw_hline); equal_pixel: UNLOCK_GCRINFO (pdc); /* Show cursor */ ShowCursor (TRUE); return ret; } ``` This function calls `FloodFillGenerator` after some necessary initialization and passes context pdc (pdc is the data structure in MiniGUI internal to represent `DC`) and two callback functions: `equal_pixel` and `_flood_fill_draw_hline`. Before this, the function gets the pixel value of starting point and stored it in `pdc->skip_pixel`. Function `equal_pixel` gets the pixel value of the given point and returns the value after comparing to `pdc->skip_pixel`; `_flood_fill_draw_hline` calls internal functions to plot horizontal line. This way can greatly decrease the complexity of codes while increase their reuse capability. Readers who are interested in this can compare the function `LineTo` between old and new `GDI` interfaces. The main aim of designing generator is to facilitate the users. For example, you can use `MiniGUI`’s curve generator to finish your job. The example below assumes that you use a circle generator to plot a circle with 4-pixel wide: ```cpp static void draw_circle_pixel (void* context, int x1, int x2, int y) { HDC hdc = (HDC) context; /*With each point on the circle as the center, fill the circle by radius 2*/ FillCircle (hdc, x1, y, 2); FillCircle (hdc, x2, y, 2); } void DrawMyCircle (HDC hdc, int x, int y, int r, gal_pixel pixel) { gal_pixel old_brush; old_bursh = SetBrushColor (hdc, pixle); /* Call circle generator */ CircleGenerator ((void*)hdc, x, y, r, draw_circle_pixel); /* Recover to the old brush color */ SetBrushColor (hdc, old_brush); } ``` The use of curve generator is very simple. Its structure is also very clear. You can learn this way during your own application developing. ## Plotting Complex Curve Based on the curve generator described in 15.7, MiniGUI provides the following basic curve plotting functions: ```cpp void GUIAPI MoveTo (HDC hdc, int x, int y); void GUIAPI LineTo (HDC hdc, int x, int y); void GUIAPI Rectangle (HDC hdc, int x0, int y0, int x1, int y1); void GUIAPI PollyLineTo (HDC hdc, const POINT* pts, int vertices); void GUIAPI SplineTo (HDC hdc, const POINT* pts); void GUIAPI Circle (HDC hdc, int sx, int sy, int r); void GUIAPI Ellipse (HDC hdc, int sx, int sy, int rx, int ry); void GUIAPI CircleArc (HDC hdc, int sx, int sy, int r, int ang1, int ang2); ``` - `MoveTo` moves current starting point of pen to given point (x, y), specified in logical coordinates. - `LineTo` draws line from current starting point to a given point (x, y), specified in logical coordinates. - Rectangle draws a rectangle with the vertices as (x0, y0) and (x1, y0). - `PollyLineTo` uses `LineTo` to draw a poly-line. Pts specify each of the vertices of poly-line while vertices specify the number of vertices. - `SplineTo` uses `LineTo` function to draw spline. Four points can determine the only one spline, that is, pts is a pointer to a 4-point structure array. - Circle draws a circle with the center of (sx, sy) and radius of r, specified in logical coordinates. - Ellipse draws an ellipse with the center of (sx, sy), x coordinate radius of rx, and y coordinate radius of ry. - `CircleArc` draws a circle arc. The center of the circle is (sx, sy), radius is r, and the starting angel and ending angle of the arc is ang1 and ang2 respectively. Ang1 and ang2 use 1/64 degree as unit. Let's see the use of Circle and Ellipse functions. Assuming there are two given points, pts[0] and pts[1]. pts[0] is the center of circle or ellipse, while pts[1] is a vertex of the bounding rectangle of them. Following code fragment plots the circle or ellipse specified by the two points: ```cpp int rx = ABS (pts[1].x - pts[0].x); int ry = ABS (pts[1].y - pts[0].y); if (rx == ry) Circle (hdc, pts[0].x, pts[0].y, rx); else Ellipse (hdc, pts[0].x, pts[0].y, rx, ry); ``` ## Filling Enclosed Curve MiniGUI provides following enclosed curve filling functions: ```cpp void GUIAPI FillBox (HDC hdc, int x, int y, int w, int h); void GUIAPI FillCircle (HDC hdc, int sx, int sy, int r); void GUIAPI FillEllipse (HDC hdc, int sx, int sy, int rx, int ry); BOOL GUIAPI FillPolygon (HDC hdc, const POINT* pts, int vertices); BOOL GUIAPI FloodFill (HDC hdc, int x, int y); ``` - `FillBox` fills a specified rectangle, the upper-left corner of which is (x, y), the width is w and the height is h. All are specified in logical coordinates. - `FillCircle` fills a given circle with center of (sx, sy), radius of r (in logical coordinates). - `FillEllips` fills a given ellipse with the center of (sx, sy), x coordinate radius of rx, and y coordinate of ry (in logical coordinates). - `FillPolygon` fills polygons. Pts means each vertex of the polygon, vertices means the number of those vertices. - `FloodFill` does the flood filling from given point (x, y). Note that all filling functions use the property of current brush (color) and affected by raster operation. The following example illustrates how to use `FillCircle` and `FillEllipse` to fill a circle or an ellipse. Assuming two given points: pts [0] and pts [1], pts [0] is the center of circle or ellipse while pts [1] is a vertex of the bounding rectangle of the circle or the ellipse. ```cpp int rx = ABS (pts[1].x - pts[0].x); int ry = ABS (pts[1].y - pts[0].y); if (rx == ry) FillCircle (hdc, pts[0].x, pts[0].y, rx); else FillEllipse (hdc, pts[0].x, pts[0].y, rx, ry); ``` ## Building Complex Region Apart from using curve generator and filling generator to plot a curve or fill a closed curve, we can also use the generators to build a complex region enclosed by closed curve. As we know, the region in MiniGUI is formed by non-intersected rectangles and meets the x-y-banned rule. Using above polygon or enclosed curve generator can regard each scan line as a rectangle with the height of one. Thus, we can use these generators to build complex region. MiniGUI uses existed enclosed curve generator to implement the following complex region generating functions: ```cpp BOOL GUIAPI InitCircleRegion (PCLIPRGN dst, int x, int y, int r); BOOL GUIAPI InitEllipseRegion (PCLIPRGN dst, int x, int y, int rx, int ry); BOOL GUIAPI InitPolygonRegion (PCLIPRGN dst, const POINT* pts, int vertices); ``` Using such functions we can initialize certain region as circle, ellipse, or polygon region. Then, we can use this region to perform hit-test (`PtInRegion` and `RectInRegion`), or select into a `DC` as the clipped region to get special painting effect. Figure 2 is a special region effect given by `gdidemo.c` of mg-samples. The code building the special regions showed by Figure 2 is listed in List 3. List 3 Creating special regions ```cpp static BLOCKHEAP my_cliprc_heap; static void GDIDemo_Region (HWND hWnd, HDC hdc) { CLIPRGN my_cliprgn1; CLIPRGN my_cliprgn2; /* Creat private heap of clipped rectangle for the region */ InitFreeClipRectList (&my_cliprc_heap, 100); /* Initialize the region, and specify that the region uses the created private heap */ InitClipRgn (&my_cliprgn1, &my_cliprc_heap); InitClipRgn (&my_cliprgn2, &my_cliprc_heap); /* Intialize two region with circle region and ellipse region respectively */ InitCircleRegion (&my_cliprgn1, 100, 100, 60); InitEllipseRegion (&my_cliprgn2, 100, 100, 50, 70); /* Render the background with a blue brush */ SetBrushColor (hdc, PIXEL_blue); FillBox (hdc, 0, 0, DEFAULT_WIDTH, 200); /* Substract region 2 from region1, and select the result into DC */ SubtractRegion (&my_cliprgn1, &my_cliprgn1, &my_cliprgn2); SelectClipRegion (hdc, &my_cliprgn1); /* Fill region 1 with red brush */ SetBrushColor (hdc, PIXEL_red); FillBox (hdc, 0, 0, 180, 200); /* Reinitialize region 1 to be a circle region, and shift region 2 right by 200 pixels */ InitCircleRegion (&my_cliprgn1, 300, 100, 60); OffsetRegion (&my_cliprgn2, 200, 0); /* Perform the XOR Exclusive (OR) operation between two regions, and select the result into DC */ XorRegion (&my_cliprgn1, &my_cliprgn1, &my_cliprgn2); SelectClipRegion (hdc, &my_cliprgn1); /* Fill the region with a red brush */ FillBox (hdc, 200, 0, 180, 200); /* Reinitialize region 1 to be circle region, and shift region 2 right by 200 pixels */ InitCircleRegion (&my_cliprgn1, 500, 100, 60); OffsetRegion (&my_cliprgn2, 200, 0); /* Perform the intersection operation of two given region, and select the result into DC */ IntersectRegion (&my_cliprgn1, &my_cliprgn1, &my_cliprgn2); SelectClipRegion (hdc, &my_cliprgn1); /* Fill the region with a red brush */ FillBox (hdc, 400, 0, 180, 200); /* Empty regions, and release the special clipped rectangle */ EmptyClipRgn (&my_cliprgn1); EmptyClipRgn (&my_cliprgn2); /* Destroy the privite leap of clipped rectangle */ DestroyFreeClipRectList (&my_cliprc_heap); } ``` ![alt](figures/15.2.jpeg) Figure 2 The output effect of special regions ## Visiting Frame Buffer Directly In new `GDI` interfaces we add the function used to directly visit the video frame buffer. The prototype is as follows: ```cpp Uint8* GUIAPI LockDC (HDC hdc, const RECT* rw_rc, int* width, int* height, int* pitch); void GUIAPI UnlockDC (HDC hdc); ``` - `LockDC` locks the specified rectangle region of given `DC`, then returns a pointer which points to the video frame buffer. When width, height and pitch are not `NULL`, the function `LockDC` will return the valid width, height and pitch of the locked rectangle. - `UnlockDC` function unlocks a locked `DC`. To lock a `DC` means that MiniGUI has entered a state of using exclusive way to visit video frame buffer. If the locked `DC` is a screen `DC`, the function will hide the mouse cursor when necessary and lock global clipping region. After locking a `DC`, program can visit locked frame buffer by using the returned pointer of this function. `DC` cannot be locked for a long time, neither calling other system calls while locking a `DC`. Assuming we use the upper-left corner of locked rectangle as the origin to build coordinate system, x coordinate is horizontally rightward while y coordinate is vertically downward. We can use following formula to calculate the address corresponding to (x, y) point (assume the returned pointer value is `frame_buffer):` ```cpp Uint8* pixel_add = frame_buffer + y * (*pitch) + x * GetGDCapability (hdc, GDCAP_BPP); ``` According to the color depth of the `DC`, we can perform read and write operation to the pixel. The following code fragment randomly fills a locked region: ```cpp int i, width, height, pitch; RECT rc = {0, 0, 200, 200}; int bpp = GetGDCapability (hdc, GDCAP_BPP); Uint8* frame_buffer = LockDC (hdc, &rc, &width, &height, &pitch); Uint8* row = frame_buffer; for (i = 0; i < *height; i++) { memset (row, rand ()%0x100, *width * bpp); row += *pitch; } UnlockDC (hdc); ``` ## Advanced Two-Dimension `GDI` Functions We added advanced two-dimension `GDI` functions in MiniGUI 1.5.x to support the development of advanced graphics applications. We can use these advanced two-dimension `GDI` function to set the advanced `GDI` properties such as pen width, pen type, and/or filling model. We will introduce the use of such advanced two-dimension `GDI` functions in this section. ### Pen and Its Properties Pen is a logical object used by MiniGUI to describe line drawing. We can determine the drawing activity by setting properties of a pen. Those properties include: - Pen types. A pen has following types (Fig. 15.3 gives several kinds of effects of pen): - `PT_SOLID`: The Solid pen. - `PT_ON_OFF_DASH`: The on/off dash pen, even segments are drawn; odd segments are not drawn. The length of every dash/solid line segment is specified by `SetPenDashes`. - `PT_DOUBLE_DASH`: The double dash pen, even segments are normally. Odd segments are drawn in the brush color if the brush type is `BT_SOLID`, or in the brush color masked by the stipple if the brush type is `BT_STIPPLED`. ![alt](figures/15.3.jpeg) Figure 3 Pen types - Width of pen. The width of pen controls the width of the plotted line segment. The width of painting pen uses pixel as unit. The default width is zero, we usually call the solid pen with the width of 0 as zero pen. General two-dimension `GDI` function of MiniGUI uses zero pen. - The cap style of pen. The cap style determines the shape of end point of the line segment (see Figure 4). It can be divided into the following styles: - `PT_CAP_BUTT`: The ends of the lines are drawn squared off and extending to the coordinates of the end point. - `PT_CAP_ROUND`: the ends of the lines are drawn as semicircles with the diameter equal to the line width and centered at the end point. - `PT_CAP_PROJECTING`: The ends of the lines are drawn squared off and extending half the width of the line beyond the end point. ![alt](figures/15,4.jpeg) Figure 4 Cap styles of pen - The join style of pen。The joining style of pen determines the way of the connection between two line segments (see Figure 5). It is divided into the following styles: - `PT_JOIN_MITER`: The sides of each line are extended to meet at an angle. - `PT_JOIN_ROUND`: a circular arc joins the sides of the two lines. - `PT_JOIN_BEVEL`: the sides of the two lines are joined by a straight line, which makes an equal angle with each line. ![alt](figures/15.5.jpeg) Figure 5 The join styles of pen Table 1 gives the operations on pen properties. Table 1 Operating functions on pen properties | *Function* |*Purpose*| | `GetPenType/SetPenType` |Get/Set pen type| | `GetPenWidth/SetPenWidth` |Get/Set pen width| | `GetPenCapStyle/SetPenCapStyle` |Get/Set pen cap style| | `GetPenJoinStyle/SetPenJoinStyle` |Get/Set pen join style| Before using dash pen, we need use `SetPenDashes` function to set the dash/solid means of pen. The prototype of this function is as follows: ```cpp void GUIAPI SetPenDashes (HDC hdc, int dash_offset, const unsigned char *dash_list, int n); ``` This function uses value in non-signed byte array to in turn represent the length of dash/solid line segments. For example, when `dash_list` = “\1\1”, the length of solid line segment is 1 pixel wide while length of dash line segment is also 1 pixel wide, it is so-called dot-line; if `dash_list=”\4\1”,` it is lineation; if `dash_list=”\4\1\1\1,` it is lineation-dotline; if `dash_list=”\4\1\1\1\1\1”,` it is lineation-dot-dotline. The above dash model can be seen in Figure 6. It should be noted that draw solid line segment itself is affected by other properties of painting pen, such as cap style of pen. ![alt](figures/15.6.jpeg) Figure 6 Dash lines The argument `dash_offset` of function `SetPenDashes` represents the starting place of dash/solid line segment in actual lines, usually is 0; the argument n means the length of `dash_list` non-signed byte array. ### Brush and Its Properties Brush is a logical object used to describe filling ways. The properties of the brush are simpler than pen. MiniGUI provides the following brush types: - `BT_SOLID`: The solid brush drawing with the current brush color. - `BT_TILED`: The tiled bitmap brush drawing with a tiled bitmap. - `BT_STIPPLED`: The transparent stippled bitmap brush drawing by using the stipple bitmap. Pixels corresponding to bits in the stipple bitmap that are set will be drawn in the brush color; pixels corresponding to bits that are not set will be left untouched. - `BT_OPAQUE_STIPPLED`: The opaque stipple bitmap brush drawing by using the stipple bitmap. Pixels corresponding to bits in the stipple bitmap that are set will be drawn in the brush color; pixels corresponding to bits that are not set will be drawn with the background color. Using function `GetBrushType/SetBrushType` can get and set the type of brush. If the brush type is not solid, we need use `SetBrushInfo` to set the bitmap or stippled bitmap used by the brush. The prototype of this function is as follows: ```cpp void GUIAPI SetBrushInfo (HDC hdc, const BITMAP *tile, const STIPPLE *stipple); ``` The tiled bitmap is object of `BITMAP` in MiniGUI, while stippled bitmap is represented by `STIPPLE` structure. We can treat stippled bitmap as monochrome bitmap, each bit of which represents a pixel. When the bit gets 1, it means that the drawing is based on brush color; when the bit gets 0, it means that the drawing is based on background color (brush type is `BT_OPAQUE_STIPPLED`) or reservation (brush type is `BT_STIPPLED`). The `STIPPLE` structure is defined as follows: ```cpp typedef struct _STIPPLE { int width; int height; int pitch; size_t size; const unsigned char* bits; } STIPPLE; ``` The following stipple bitmap can be used to represent slanting squares: ```cpp const unsigned char stipple_bits [] = "\x81\x42\x24\x18\x18\x24\x42\x81"; static STIPPLE my_stipple = { 8, 8, 1, 8, stipple_bits }; ``` There is an important concept when using brush, that is, the origin point of brush. The origin point of a brush determines the starting filling position of the brush bitmap. The upper-left corner of tiled bitmap or stippled bitmap will be aligned to the brush origin. By default, the brush origin is the origin of `DC`. Sometimes application need to reset the brush origin, it can call function `SetBrushOrigin`. ### Advanced Two-Dimension Drawing Functions When configuring MiniGUI, we can enable the advanced two-dimension `GDI` functions by using option `--enable-adv2dapi`. When MiniGUI includes the interface of advanced two-dimension `GDI` functions, all of the filling-typed functions mentioned before will be affected by the properties of current brush. These functions include `FillBox`, `FillCircle`, `FillEllipse`, `FillPolygon`, `FloodFill`, and so on. However, basic line/curve drawing functions will not be affected by the properties of pen. Those functions include `MoveTo/LineTo`, Rectangle, `PolyLineTo`, `SplineTo`, Circle, Ellipse, and `CircleArc`. These basic line/curve drawing functions still use zero pen to draw. We introduced some advanced two-dimension drawing functions, the activity of which will be affected by pen and brush: ```cpp void GUIAPI LineEx (HDC hdc, int x1, int y1, int x2, int y2); void GUIAPI ArcEx (HDC hdc, int sx, int sy, int width, int height, int ang1, int ang2); void GUIAPI FillArcEx (HDC hdc, int x, int y, int width, int height, int ang1, int ang2); void GUIAPI PolyLineEx (HDC hdc, const POINT *pts, int nr_pts); void GUIAPI PolyArcEx (HDC hdc, const ARC *arcs, int nr_arcs); void GUIAPI PolyFillArcEx (HDC hdc, const ARC *arcs, int nr_arcs); ``` - `LineEx` function plots a beeline according to the properties of current pen/brush. The line is from (x1, y1) to (x2, y2). - `ArcEx` function plots an arc line according to the properties of current pen/brush. The center of the arc is (x, y), the width of the bounding box of the arc is width; the height of the bounding box of the arc is height; the starting angel the arc is ang1, in 1/64ths of a degree; ang2 is the end angel relative to starting angel, in 1/64ths of a degree. If ang2 is positive, representing anti-clockwise; ang2 is negative, representing clockwise. When ang2 is more than or equals to 360x64, it means an entire circle or ellipse, but not an arc. - `FillArcEx` function fills an arc-shaped sector. The meaning of parameter is same as `ArcEx`. - `PolyLinEx` function plots multiple lines according to the properties of current pen/brush. If having to joint lines, it will perform the joint according to the properties of current pen. - `PolyArcEx` function plots multiple arcs according to the properties of current painting brush. If having to joint arcs, it will perform the joint according to the properties of pen. This function uses `ARC` structure to describe the parameter of each arc. The structure is defined as follows: ```cpp typedef struct _ARC { /** the x coordinate of the left edge of the bounding rectangle. */ int x; /** the y coordinate of the left edge of the bounding rectangle. */ int y; /** the width of the bounding box of the arc. */ int width; /** the height of the bounding box of the arc. */ int height; /** * The start angle of the arc, relative to the 3 o'clock position, * counter-clockwise, in 1/64ths of a degree. */ int angle1; /** * The end angle of the arc, relative to angle1, in 1/64ths of a degree. */ int angle2; } ARC; ``` `PolyFillArcEx` function fills multiple arcs. This function uses `ARC` structure to describe the parameter of each arc. ### Using Advanced Two-Dimension `GDI` Functions The code in List 5 uses the above advanced two-dimension `GDI` function to draw some graphics objects. Figure 7 gives the output effect of this code. List 5 Using advanced two-dimension `GDI` functions ```cpp #ifdef _ADV_2DAPI /* Define grid stripple bitmap */ const unsigned char stipple_bits [] = "\x81\x42\x24\x18\x18\x24\x42\x81"; static STIPPLE my_stipple = { 8, 8, 1, 8, stipple_bits }; /* Example code of advanced 2D GDI functions */ void GDIDemo_Adv2DAPI (HWND hWnd, HDC hdc) { POINT pt [10]; BITMAP bitmap; /* Load a bitmap as brush tile bitmap */ if (LoadBitmap (hdc, &bitmap, "res/sample.bmp")) return; /* Set pen type, dash style and width */ SetPenType (hdc, PT_SOLID); SetPenDashes (hdc, 0, "\1\1", 2); SetPenWidth (hdc, 5); /* Set the end point style of pen is “round end point” */ SetPenCapStyle (hdc, PT_CAP_ROUND); /* Plot a line point */ LineEx (hdc, 10, 10, 50, 50); /* Set pen jointing style as “bevel joining” */ SetPenJoinStyle (hdc, PT_JOIN_BEVEL); /* Plot poly line segment */ pt [0].x = 20; pt [0].y = 20; pt [1].x = 80; pt [1].y = 20; pt [2].x = 80; pt [2].y = 80; pt [3].x = 20; pt [3].y = 80; pt [4].x = 20; pt [4].y = 20; PolyLineEx (hdc, pt, 5); /* Set pen width to be 20, pen color to be red, pen end point style to /*be “round end point” */ SetPenWidth (hdc, 20); SetPenColor (hdc, PIXEL_red); SetPenCapStyle (hdc, PT_CAP_ROUND); /* Plot a line segment */ LineEx (hdc, 80, 80, 400, 300); /* Set pen color to be blue */ SetPenColor (hdc, PIXEL_blue); /* Plot an arc across thid quadrant and forth quadrant */ ArcEx (hdc, 100, 100, 200, 300, 180*64, 180*64); /* Set brush type as solid */ SetBrushType (hdc, BT_SOLID); /* Set brush color as green */ SetBrushColor (hdc, PIXEL_green); /* Fill arc from 0 degree to 120 degree */ FillArcEx (hdc, 100, 0, 200, 100, 0, 120*64); /* Set brush type as tile */ SetBrushType (hdc, BT_TILED); SetBrushInfo (hdc, &bitmap, &my_stipple); /* Set the origin of brush */ SetBrushOrigin (hdc, 100, 100); /* Fill arc from 0 to 270 degree with tile brush */ FillArcEx (hdc, 100, 100, 200, 100, 0, 270*64); /* Set brush type as transparent stipple brush, to be filled with grid */ SetBrushType (hdc, BT_STIPPLED); /* Fill arc from 0 to 360 degree with the transparent stipple brush */ FillArcEx (hdc, 100, 300, 200, 100, 0, 360*64); /* Set pen type as double dash line, fill the dash line segemnt with stipple brush */ SetPenType (hdc, PT_DOUBLE_DASH); /* Set the dash and solid length of pen */ SetPenDashes (hdc, 0, "\20\40", 2); /* Set the pen end point style as BUTT end point */ SetPenCapStyle (hdc, PT_CAP_BUTT); /* Set the dash width as 20 */ SetPenWidth (hdc, 20); /* Plot a line segment */ LineEx (hdc, 500, 0, 20, 100); /* Set the pen type as opaque stipple bitmap */ SetBrushType (hdc, BT_OPAQUE_STIPPLED); /* Fill an arc across thid quadrant and forth quadrant using opaque stipple bitmap */ ArcEx (hdc, 400, 100, 200, 300, 180*64, 180*64); /* Unload bitmap */ UnloadBitmap (&bitmap); } #endif /* _ADV_2DAPI */ ``` ![alt](figures/15.7.jpeg) Figure 7 The output of advanced two-dimension `GDI` functions ## Support for Slave Screens MiniGUI supports the slave screens if there are multiple video devices installed. The slave screen only can display information and cannot receive any input at all. The slave screen is abstracted as a `DC` object. So `GDI` functions can be called for the slave screen. ### Creating Slave Screen The following function can used to open the slave screen: ```cpp HDC GUIAPI InitSlaveScreen (const char *name, cnost char *mode); ``` `InitSlaveScreen` return a graphics device context handle by a special device name and display mode. The argument `name` specifies what NEWGAL engine the slave screen uses, and `mode` specifies the resolution and color depth of the slave screen. The following code is a example for opening a slave screen. ```cpp HDC hdc; const char *engine = "qvfb"; const char *mode = "640x480-16bpp"; hdc = InitSlaveScreen (engine, mode); ``` The graphics device context handle returned by `InitSlaveScreen` can call `GDI` functions in MiniGUI to plot in the slave screen, and the process is completely same as normal `DC`. ### Destroying Slave Screen The following function can be used to destroy the slave screen; you should use this function to release the internal resource associated with the slave screen: ```cpp void GUIAPI TerminateSlaveScreen(HDC hdc); ``` Here, `hdc` is a graphic device context handle returned by `InitSlaveScreen`. ---- [<< Handling and Rendering of Text](MiniGUIProgGuidePart3Chapter02.md) | [Table of Contents](README.md) | [mGPlus Programming >>](MiniGUIProgGuidePart3Chapter04.md) [Release Notes for MiniGUI 3.2]: /supplementary-docs/Release-Notes-for-MiniGUI-3.2.md [Release Notes for MiniGUI 4.0]: /supplementary-docs/Release-Notes-for-MiniGUI-4.0.md [Showing Text in Complex or Mixed Scripts]: /supplementary-docs/Showing-Text-in-Complex-or-Mixed-Scripts.md [Supporting and Using Extra Input Messages]: /supplementary-docs/Supporting-and-Using-Extra-Input-Messages.md [Using CommLCD NEWGAL Engine and Comm IAL Engine]: /supplementary-docs/Using-CommLCD-NEWGAL-Engine-and-Comm-IAL-Engine.md [Using Enhanced Font Interfaces]: /supplementary-docs/Using-Enhanced-Font-Interfaces.md [Using Images and Fonts on System without File System]: /supplementary-docs/Using-Images-and-Fonts-on-System-without-File-System.md [Using SyncUpdateDC to Reduce Screen Flicker]: /supplementary-docs/Using-SyncUpdateDC-to-Reduce-Screen-Flicker.md [Writing DRM Engine Driver for Your GPU]: /supplementary-docs/Writing-DRM-Engine-Driver-for-Your-GPU.md [Writing MiniGUI Apps for 64-bit Platforms]: /supplementary-docs/Writing-MiniGUI-Apps-for-64-bit-Platforms.md [Quick Start]: /user-manual/MiniGUIUserManualQuickStart.md [Building MiniGUI]: /user-manual/MiniGUIUserManualBuildingMiniGUI.md [Compile-time Configuration]: /user-manual/MiniGUIUserManualCompiletimeConfiguration.md [Runtime Configuration]: /user-manual/MiniGUIUserManualRuntimeConfiguration.md [Tools]: /user-manual/MiniGUIUserManualTools.md [Feature List]: /user-manual/MiniGUIUserManualFeatureList.md [MiniGUI Overview]: /MiniGUI-Overview.md [MiniGUI User Manual]: /user-manual/README.md [MiniGUI Programming Guide]: /programming-guide/README.md [MiniGUI Porting Guide]: /porting-guide/README.md [MiniGUI Supplementary Documents]: /supplementary-docs/README.md [MiniGUI API Reference Manuals]: /api-reference/README.md [MiniGUI Official Website]: http://www.minigui.com [Beijing FMSoft Technologies Co., Ltd.]: https://www.fmsoft.cn [FMSoft Technologies]: https://www.fmsoft.cn [HarfBuzz]: https://www.freedesktop.org/wiki/Software/HarfBuzz/