FillRects: StippledFillRects, OpStippledFillRects -- stipple-handling routines


#include "nfbGCStr.h"

void xxx[Op]StippledFillRects ( GCPtr pGC, DrawablePtr pDraw, BoxPtr pbox, unsigned int nbox) ;

xxx is the routine's prefix. Valid values are gen to use the default routine or your driver's prefix if you are rewriting this routine to use the specific capabilities of your hardware.


These routines fill the rectangles described by pbox and nbox based on members of pGC required by the fill style. They can be used to implement solid, stippled, or stippled and tiled fill styles. Overall, stipples are similar to tiles except the initial image to be used as a pattern is a bitmap. StippledFillRects( ) implements a transparent stipple fill; OpStippledFillRects( ) implements an opaque stipple fill. The syntax of the two routines is identical.

The parameters are:

points to an X GC structure. With routines that have a GC pointer as their first argument, the alu, planemask, and fg colors are extracted from this structure. Also, all information associated with the stipple, including a pointer to its image, is extracted from this structure. See the sample code below for how this is done.

Pointer to a DrawablePtr structure used to access your screen private data. The pDraw->pScreen member points to the ScreenRec(D4nfb) structure; your screen private is connected to the bottom of the ScreenRec structure.

points to the first in a series of BoxRec(D4nfb) structures that describe the rectangles to be filled. pbox[0] is the first rectangle, pbox[1] is the second, and pbox[nbox - 1]} is last.

number of rectangles to be filled.

Exit codes



genOpStippledFillRects has the same syntax as the genStippledFillRects routine. The semantic difference is that genOpStippledFillRects fills rectangles with opaque stipples. This makes its drawing algorithm nearly identical to TileRects(D3nfb) code except that when the stipple is drawn to off-screen memory it should be drawn with DrawOpaqueMonoImage(D3nfb) using all the planes (unlike StippledFillRects which draws a bitmap at that point) and using the fg and bg colors extracted from the pGC pointer.

If you have no off-screen memory available to help rendering stippled rectangles, then it is unlikely that you will be able to improve on the performance of the gen code. Also, if your hardware is unable to transparently expand bitmaps from off-screen memory (which is a limitation of the Weitek P9000), then you will probably only be able to implement the opaque stippled rectangle fill routine, OpStippledFillRects.


Here is the transparent stippled drawing code for the S3 86C928. First, a macro is defined for expand ``blitting'' a rectangle from one part of screen memory to another. Specifically, this will only be used for ``blitting'' the stipple from off-screen to on-screen memory. For more information, see ``Blit'' in Developing NFB graphics adapter drivers.
   #define NTE_WORK_AREA_STIP(src, dest_x, dest_y, width, height) \
   { \
           NTE_CLEAR_QUEUE(7); \
           NTE_CURX((src)->x); \
           NTE_CURY((src)->y); \
           NTE_DESTX_DIASTP(dest_x); \
           NTE_DESTY_AXSTP(dest_y); \
           NTE_MAJ_AXIS_PCNT((width) - 1); \
           NTE_MIN_AXIS_PCNT((height) - 1); \
           NTE_CMD(S3C_BLIT_XP_YP_Y); \

void NTE(StippledFillRects)( GCPtr pGC, DrawablePtr pDraw, BoxPtr pbox, unsigned int nbox) { int w, h, min_width, min_height, max_width, max_height; int stride, width, height; DDXPointPtr patOrg; PixmapPtr pStip; unsigned char *image; nfbGCPrivPtr pGCPriv = NFB_GC_PRIV(pGC); unsigned long fg = pGCPriv->rRop.fg; unsigned char alu = pGCPriv->rRop.alu; unsigned long planemask = pGCPriv->rRop.planemask; BoxRec *p, box; ntePrivateData_t *ntePriv = NTE_PRIVATE_DATA(pDraw->pScreen); DDXPointRec src;

The next three lines extract some stipple information from the pGC structure. w will contain the width of the stipple in bits, and h will contain the height.
           pStip = pGC->stipple;
           w = pStip->drawable.width;
           h = pStip->drawable.height;

min_width = w * 2; min_height = h * 2;

if (min_width > ntePriv->wawidth || min_height > ntePriv->waheight) {

Stipples are subject to patOrg offset rules exactly the same as tiles. This algorithm uses a similar approach to that of the tile filling algorithm so if we can't fit the stipple in off-screen memory, then bail out to the gen code.
                genStippledFillRects(pGC, pDraw, pbox, nbox);
The next three lines extract more information about the stipple from various parts of the pGC structure. image points to the bitmap pattern that is to be used as the stipple. stride is the value in bytes that should be added to image to move from one line of the stipple image to the next.

patOrg is the DDXPointRec(D4nfb) that defines the offset values that must be used when filling each rectangle with the stipple.

        image = pStip->devPrivate.ptr;
        stride = pStip->devKind;
        patOrg = &(pGCPriv->screenPatOrg);

max_width = w; max_height = h; p = pbox; width = p->x2 - p->x1; height = p->y2 - p->y1; if (width > max_width) max_width = width; if (height > max_height) max_height = height; p = &pbox[nbox / 2]; width = p->x2 - p->x1; height = p->y2 - p->y1; if (width > max_width) max_width = width; if (height > max_height) max_height = height; p = &pbox[nbox - 1]; width = p->x2 - p->x1; height = p->y2 - p->y1; if (width > max_width) max_width = width; if (height > max_height) max_height = height;

if (max_width > ntePriv->wawidth) max_width = ntePriv->wawidth; if (max_height > ntePriv->waheight) max_height = ntePriv->waheight;

max_width = (max_width / w) * w; max_height = (max_height / h) * h;

if (max_width < min_width) max_width = min_width; if (max_height < min_height) max_height = min_height;

The above section of code samples the sizes of three rectangles in an attempt to determine the optimal size of the off-screen stipple. This is similar to the tile rectangle filling code.
        box.x1 = ntePriv->wax;
        box.y1 = ntePriv->way;
        box.x2 = box.x1 + w;
        box.y2 = box.y1 + h;
The next line draws the stipple to off-screen memory on the graphics adapter. Note that we must use DrawOpaqueMonoImage(D3nfb) when drawing to off-screen memory. Using DrawMonoImage would result in garbage appearing in the stipple pattern. Also note that we only need to draw to a single plane.
        NTE(DrawOpaqueMonoImage)(&box, image, 0, stride, ~0, 0, GXcopy, 1,
        box.x2 = box.x1 + max_width;
        box.y2 = box.y1 + max_height;
The following line replicates the off-screen stipple out to the optimal size determined above. Note that once again a planemask with only 1 bit is used.
        nfbReplicateArea(&box, w, h, 1, pDraw);

max_width -= w; max_height -= h;


while (nbox--) {

Similar to TileRects(D3nfb), we now ``blit'' the stipple in off-screen memory to on-screen memory. The only significant differences are;
                width = pbox->x2 - pbox->x1;
                height = pbox->y2 - pbox->y1;

src.x = (pbox->x1 - patOrg->x) % (int)w; if (src.x < 0) src.x += w; src.x += ntePriv->wax; src.y = (pbox->y1 - patOrg->y) % (int)h; if (src.y < 0) src.y += h; src.y += ntePriv->way;

if (width < max_width && height < max_height) { NTE_WORK_AREA_STIP(&src, pbox->x1, pbox->y1, width, height); } else nteStippleAreaSlow(pbox, &src, max_height, max_width, ntePriv); ++pbox; }


static void nteStippleAreaSlowXExpand( BoxRec *pbox, DDXPointRec *src, int max_width, ntePrivateData_t *ntePriv) { int width, height, x, y; int chunks, extra_width;

width = pbox->x2 - pbox->x1; height = pbox->y2 - pbox->y1; x = pbox->x1; y = pbox->y1; chunks = width / max_width; extra_width = width % max_width;

NTE_BEGIN(ntePriv->regs); while (chunks--) { NTE_WORK_AREA_STIP(src, x, y, max_width, height); x += max_width; } if (extra_width) NTE_WORK_AREA_STIP(src, x, y, extra_width, height); NTE_END(); }
static void nteStippleAreaSlow( BoxRec *pbox, DDXPointRec *src, int max_height, int max_width, ntePrivateData_t *ntePriv) { int height; int chunks, extra_height; BoxRec screen_box;

height = pbox->y2 - pbox->y1; chunks = height / max_height; extra_height = height % max_height; screen_box.x1 = pbox->x1; screen_box.x2 = pbox->x2; screen_box.y1 = pbox->y1; while (chunks--) { screen_box.y2 = screen_box.y1 + max_height; nteStippleAreaSlowXExpand(&screen_box, src, max_width, ntePriv); screen_box.y1 += max_height; } if (extra_height) { screen_box.y2 = screen_box.y1 + extra_height; nteStippleAreaSlowXExpand(&screen_box, src, max_width, ntePriv); } }

Version applicability

This function is supported for NFB drivers on all releases of SCO OpenServer 5, SVR5, and AIX 5L.

Source files

Routine source

Driver source file


BoxRec(D4nfb), nfbGCOps(D4nfb)
19 June 2005
© 2005 The SCO Group, Inc. All rights reserved.
OpenServer 6 and UnixWare (SVR5) HDK - June 2005