|
|
#include "nfbGCStr.h"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.void xxx[Op]StippledFillRects ( GCPtr pGC, DrawablePtr pDraw, BoxPtr pbox, unsigned int nbox) ;
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:
pGCalu, 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.
pDrawpboxpbox[0] is the first rectangle,
pbox[1] is the second,
and pbox[nbox - 1]} is last.
nboxfg 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.
#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);
return;
}
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,
pDraw);
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);Similar to TileRects(D3nfb), we now ``blit'' the stipple in off-screen memory to on-screen memory. The only significant differences are;max_width -= w; max_height -= h;
NTE_BEGIN(ntePriv->regs); NTE_CLEAR_QUEUE(6); NTE_FRGD_COLOR(fg); NTE_PIX_CNTL(NTE_VIDEO_MEMORY_DATA_MIX); NTE_WRT_MASK(planemask); NTE_RD_MASK(1); NTE_FRGD_MIX(NTE_FRGD_SOURCE, NTE(RasterOps)[alu]); NTE_BKGD_MIX(NTE_BKGD_SOURCE, NTE(RasterOps)[GXnoop]);
while (nbox--) {
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;
}
NTE_CLEAR_QUEUE(2);
NTE_RD_MASK(NTE_ALLPLANES);
NTE_PIX_CNTL(0);
NTE_END();
}
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);
}
}