#ifndef lint
static char sccsid[] = "@(#)cg2_shrop.c 9.2 88/01/19 Copyright 1985 Sun Micro";
#endif


/*-
 * Copyright (c) 1984 by Sun Microsystems, Inc. 
 *
 * "Might as well be frank, monsieur.  It would take a miracle to get you out
 *  of Casablanca and the Germans have outlawed miracles." 
 */

/*
 * Sun2 Color pixrect rasterop 
 */

#ifdef REF
#include <sys/types.h>
#include <ref/config.h>
#endif
#include "shape.h"
#include <pixrect/pr_util.h>
#include <pixrect/memreg.h>
#include <pixrect/cg2reg.h>
#include <pixrect/cg2var.h>
#include <pixrect/memvar.h>
#include "trap_step.h"

#define resolution unused,0

#undef rop_fastloop
#define	rop_fastloop(n, op) { register short j = n; while (j-- != 0) { op; }}


extern struct pixrectops mem_ops;
extern      magic_hack_bgcolor;

static
short       mrc_lmasktable[] = {0x0000, 0x8000, 0xC000, 0xE000,
				0xF000, 0xF800, 0xFC00, 0xFE00,
				0xFF00, 0xFF80, 0xFFC0, 0xFFE0,
				0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE};
static
short       mrc_rmasktable[] = {0x7FFF, 0x3FFF, 0x1FFF, 0x0FFF,
				0x07FF, 0x03FF, 0x01FF, 0x00FF,
				0x007F, 0x003F, 0x001F, 0x000F,
				0x0007, 0x0003, 0x0001, 0x0000};

/*
 * Rasterop involving cg2 colorbuf.  Normally we are called as the
 * destination via one of the macros in <pixrect/pixrect.h>, but we may
 * also be the source if another implementor wants us to retrieve bits
 * into memory. 
 */
cg2_shaperop(dst_pr, shape, OP, src_pr, sdx, sdy)
    struct pixrect *dst_pr, *src_pr;
    struct shape *shape;
{
    register u_char *bx,
               *by,
               *ma;		/* ROOM FOR ONE MORE REGISTER */
    u_char     *ma_top;
    register    ma_vert,
                linebytes;
    register short w,
                color;
    struct cg2fb *fb;
    struct cg2pr *sbd,
               *dbd;
    int         errs = 0;
    int         skew;
    struct pr_prpos tem1,
                tem2;
    struct pr_subregion dst;
    struct pr_prpos src;
    struct shape nextshape;
    if (shape == 0)
	return 0;
    if (dst_pr == src_pr)
	return generic_shaperop(dst_pr, shape, OP, src_pr, sdx, sdy);
    tem1.pr = 0;
    while (1) {
	int         op = OP;
	dst.pr = dst_pr;
	if (shape->size.x < 0) {
	    dst.pos.x = 0;
	    dst.pos.y = 0;
	    dst.size.x = 16000;
	    dst.size.y = 16000;
	}
	else {
	    dst.pos.x = shape->pos.x;
	    dst.pos.y = shape->pos.y;
	    dst.size.x = shape->size.x;
	    dst.size.y = shape->size.y;
	}
	src.pr = src_pr;
	src.pos.x = dst.pos.x - sdx;
	src.pos.y = dst.pos.y - sdy;
	if (op & PIX_DONTCLIP)
	    op &= ~PIX_DONTCLIP;
	else
	    pr_clip(&dst, &src);
	if (dst.size.x <= 0 || dst.size.y <= 0)
	    return (0);
	if (shape->is_rect)	/* The ordinary case */
	    cg2_rop(dst.pr, dst.pos.x, dst.pos.y,
		    dst.size.x, dst.size.y,
		    OP,
		    src.pr, src.pos.x, src.pos.y);
	else {			/* trapezon bounded case */
	    struct fine_trap_state trap;
	    int         ylimit = dst.pos.y + dst.size.y;
	    if (shape->trapset->top > dst.pos.y) {
		if ((dst.size.y += (w = dst.pos.y - shape->trapset->top)) <= 0)
		    goto Continue;
		dst.pos.y -= w;
		src.pos.y -= w;
	    }
	    if (shape->trapset->bottom >= ylimit
		|| (dst.size.y = (ylimit = shape->trapset->bottom) - dst.pos.y) > 0) {
		init_fine_trap(&trap, shape->trapset);
		fast_step_down_trap_to(&trap, dst.pos.y);
		if (dst.pr->pr_ops->pro_rop != cg2_rop) {
		    if (src_pr->pr_ops->pro_rop != cg2_rop)
			return (-1);	/* neither src nor dst is cg */
		    printf("Case 1 not yet implemented\n");

		    /*
		     * Case 1 -- we are the source for the rasterop, but
		     * not the destination. This is a rasterop from the
		     * color frame buffer to another kind of pixrect. If
		     * the destination is not memory, then we will go
		     * indirect by allocating a memory temporary, and then
		     * asking the destination to rasterop from there into
		     * itself. Also, since rasterop hardware doesnt
		     * operate on reads from the frame buffer, if op !=
		     * SRC we must rop with PIX_SRC to temporary memory
		     * then rop with op from memory to memory. 
		     */
		    sbd = cg2_d(src_pr);
		    src.pos.x += sbd->cgpr_offset.x;
		    src.pos.y += sbd->cgpr_offset.y;

		    if (MP_NOTMPR(dst.pr)) {
			tem1.pr = dst.pr;
			tem1.pos = dst.pos;
			dst.pr = mem_create(dst.size.x, dst.size.y, CG2_DEPTH);
			dst.pos.x = dst.pos.y = 0;
		    }
		    tem2.pr = 0;
		    if ((op & PIX_SET) != PIX_SRC) {	/* handle non PIX_SRC
							 * ops since */
			tem2.pr = dst.pr;	/* hdwre rops dont work on
						 * fb reads */
			tem2.pos = dst.pos;
			dst.pr = mem_create(dst.size.x, dst.size.y, CG2_DEPTH);
			dst.pos.x = dst.pos.y = 0;
		    }

		    fb = cg2_fbfrompr(src_pr);
		    fb->ppmask.reg = 255;
		    fb->status.reg.ropmode = SRWPIX;
		    linebytes = cg2_linebytes(fb, SRWPIX);
		    by = cg2_roppixaddr(fb, src.pos.x, src.pos.y);
		    ma_top = mprs8_addr(dst);
		    ma_vert = mpr_mdlinebytes(dst.pr);

		    w = dst.size.y;
		    while (w-- > 0) {
			bx = by;
			ma = ma_top;
			ma_top += ma_vert;
			rop_fastloop(dst.size.x, *ma++ = *bx++)
			    by += linebytes;
		    }
		    if (tem2.pr) {	/* temp mem to mem for non SRC op */
			errs |= (*tem2.pr->pr_ops->pro_rop)
			    (tem2, dst.size, op, dst.pr, dst.pos);
			mem_destroy(dst.pr);
			dst.pr = tem2.pr;
			dst.pos = tem2.pos;
		    }
		    if (tem1.pr) {	/* temp mem to other kind of
					 * pixrect */
			errs |= (*tem1.pr->pr_ops->pro_rop)
			    (tem1, dst.size, PIX_SRC, dst.pr, dst.pos);
			mem_destroy(dst.pr);
			tem1.pr = 0;
		    }
		}
		else {
		    /*
		     * Case 2 -- writing to the sun1 color frame buffer
		     * this consists of 4 different cases depending on
		     * where the data is coming from:  from nothing, from
		     * memory, from another type of pixrect, and from the
		     * frame buffer itself. 
		     */
		    short       xoff,
		                yoff;
		    dbd = cg2_d(dst.pr);
		    xoff = dbd->cgpr_offset.x;
		    yoff = dbd->cgpr_offset.y;
		    dst.pos.x += xoff;
		    /* dst.pos.y += yoff; */
		    fb = cg2_fbfrompr(dst.pr);
		    color = PIX_OPCOLOR(op);
		    op = (op >> 1) & 0xF;

		    if (src_pr == 0) {
			/*
			 * Case 2a: source pixrect is specified as null.
			 * In this case we interpret the source as color. 
			 */
			short       ropmode,
			            nodst;
			short       xlimit = dst.pos.x + dst.size.x;
			short       ylimit = dst.pos.y + dst.size.y;
			fb->ppmask.reg = dbd->cgpr_planes;
			cg2_setfunction(fb, CG2_ALLROP, op);
			fb->ropcontrol[CG2_ALLROP].ropregs.mrc_pattern = 0;
			fb->ropcontrol[CG2_ALLROP].prime.ropregs.mrc_source2 =
			    color | (color << 8);	/* load color in src */


			nodst = (PIXOP_NEEDS_DST(op << 1) == 0);
			if (nodst)
			    ropmode = PRRWRD;	/* load dst when necessary */
			else
			    ropmode = PWRWRD;	/* but never load src */
			fb->status.reg.ropmode = PWRWRD;	/* ld dst for mask */

			linebytes = cg2_linebytes(fb, PWRWRD);
			while (dst.pos.y < ylimit) {
			    register    x1 = dst.pos.x;
			    register    x2 = xlimit;
			    register    height;
			    trap.x1 += xoff;
			    trap.x2 += xoff;
			    if (trap.x1 > x1)
				x1 = trap.x1;
			    if (trap.x2 < x2)
				x2 = trap.x2;
			    /*-			while (max(trap.next.x1, dst.pos.x) == x1
			     *			       && min(trap.next.x2, xlimit) == x2 && trap.next.y < ylimit)
			     *			    trap.next = *trap.seg++;
			     *			height = (trap.seg < trap.limit ? trap.next.y : shape->trapset->bottom) - dst.pos.y; */
			    height = trap.next.y - dst.pos.y;
			    if (height <= 0)
				break;
			    if (height + dst.pos.y > ylimit)
				height = ylimit - dst.pos.y;
			    by = (u_char *) cg2_ropwordaddr(fb, 0, x1, dst.pos.y + yoff);
			    trap.x1 = trap.next.x1;
			    trap.x2 = trap.next.x2;
			    dst.pos.y = trap.next.y;
			    trap.next = *trap.seg++;
			    if (x1 < x2) {
				fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask1 =
				    mrc_lmasktable[x1 & 0xF];
				fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask2 =
				    mrc_rmasktable[(x2 - 1) & 0xF];
				w = cg2_prskew(x1);
				w = (x2 - x1 + w - 1) >> 4;
				cg2_setwidth(fb, CG2_ALLROP, w, w);
				cg2_setshift(fb, CG2_ALLROP, 0, 1);
				switch (w) {
				case 0:
				    w = height;
				    while (w-- != 0) {
					*((short *) by) = color;
					by += linebytes;
				    }
				    break;
				case 1:
				    w = height;
				    while (w-- != 0) {
					((short *) by)[0] = color;
					((short *) by)[1] = color;
					by += linebytes;
				    }
				    break;
				default:
				    if (nodst) {
					cg2_setwidth(fb, CG2_ALLROP, 2, 2);
					w -= 2;
					while (height-- != 0) {
					    bx = by;
					    *((short *) bx)++ = color;
					    *((short *) bx)++ = color;
					    fb->status.reg.ropmode = ropmode;
					    rop_fastloop(w, *((short *) bx)++ = color);
					    fb->status.reg.ropmode = PWRWRD;
					    *((short *) bx)++ = color;
					    by += linebytes;
					}
				    }
				    else {
					while (height-- != 0) {
					    bx = by;
					    rop_fastloop(w, *((short *) bx)++ = color);
					    *((short *) bx)++ = color;
					    by += linebytes;
					}
				    }
				}
			    }
			}
		    }
		    else if (src_pr->pr_ops->pro_rop == cg2_rop) {
			/*
			 * Case 2b: rasterop within the frame buffer.
			 * Examine the source and destination for overlap
			 * so we dont clobber ourselves. 
			 *
			 * BUG: If there are more than 1 of our kind of frame
			 * buffer another clause is required in the if
			 * statement above. We should treat a different
			 * sun-1 frame buffer as though it were a foreign
			 * device. 
			 */
			short       prime,
			            srcx,
			            ccxlimit = dst.pos.x + dst.size.x,
			            ropmode;
			int         dir;

			sbd = cg2_d(src_pr);	/* set src and dir */
			src.pos.x += sbd->cgpr_offset.x;
			srcx = src.pos.x;
			src.pos.y += sbd->cgpr_offset.y;
			fb->ppmask.reg = dbd->cgpr_planes;
			cg2_setfunction(fb, CG2_ALLROP, op);
			fb->ropcontrol[CG2_ALLROP].ropregs.mrc_pattern = 0;
			dir = rop_direction(src.pos, sbd->cgpr_offset,
					    dst.pos, dbd->cgpr_offset);
			linebytes = cg2_linebytes(fb, PWRWRD);
			if (rop_isdown(dir)) {	/* adjust direction */
			    linebytes = -linebytes;
			    src.pos.y += dst.size.y - 1;
			    dst.pos.y += dst.size.y - 1;
			    fast_step_down_trap_to(&trap, dst.pos.y);
			    stepping_up_trap(&trap, shape->trapset);
			}
			cg2_setshift(fb, CG2_ALLROP, (dst.pos.x - srcx) & 0xF,
				     rop_isright(dir) ? 0 : 1);
			while (dst.size.y > 0) {
			    short       ccx1 = dst.pos.x;
			    short       ccx2 = ccxlimit;
			    register short ccheight;
			    src.pos.x = srcx;
			    trap.x1 += xoff;
			    trap.x2 += xoff;
			    if (trap.x1 > ccx1) {
				src.pos.x += trap.x1 - ccx1;
				ccx1 = trap.x1;
			    }
			    if (trap.x2 < ccx2)
				ccx2 = trap.x2;
			    if (rop_isdown(dir)) {
#ifdef undef
				while (max(trap.next.x1, dst.pos.x) == ccx1
				       && min(trap.next.x2, ccxlimit) == ccx2 && trap.seg > trap.start) {
				    trap.y = trap.next.y;
				    trap.next = *--trap.seg;
				}
#endif
				if ((ccheight = dst.pos.y + 1 - trap.y) <= 0)
				    break;
				if (trap.seg > trap.start) {
				    trap.y = trap.next.y;
				    trap.x1 = trap.next.x1;
				    trap.x2 = trap.next.x2;
				    trap.next = *--trap.seg;
				}
			    }
			    else {
#ifdef undef
				while (max(trap.next.x1, dst.pos.x) == ccx1
				       && min(trap.next.x2, ccxlimit) == ccx2 && trap.next.y < ylimit)
				    trap.next = *trap.seg++;
#endif
				if (trap.seg < trap.limit) {
				    if ((ccheight = trap.next.y - trap.y) <= 0)
					break;
				    trap.y = trap.next.y;
				    trap.x1 = trap.next.x1;
				    trap.x2 = trap.next.x2;
				    trap.next = *trap.seg++;
				}
				else {
				    if ((ccheight = shape->trapset->bottom - trap.y) <= 0)
					break;
				    trap.y += ccheight;
				}
			    }
			    if (ccheight > dst.size.y)
				ccheight = dst.size.y;
			    dst.size.y -= ccheight;
			    skew = cg2_prskew(ccx1);	/* words to xfer - 1 */
			    w = (ccx2 - ccx1 + skew - 1) >> 4;
			    cg2_setwidth(fb, CG2_ALLROP, w, w);	/* set width,opcount */

			    if (PIXOP_NEEDS_DST(op << 1))
				ropmode = PWRWRD;	/* set ropmode */
			    else
				ropmode = PRRWRD;
			    /* set src extract */
			    if (rop_isright(dir) && w) {	/* addresses inc toward
								 * left */
				src.pos.x += ccx2 - ccx1 - 1;
				fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask1 =
				    mrc_rmasktable[(ccx2 - 1) & 0xF];
				fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask2 =
				    mrc_lmasktable[ccx1 & 0xF];
				ccx1 = ccx2 - 1;
				prime = cg2_prskew(src.pos.x) <= cg2_prskew(ccx1);
			    }
			    else {	/* addresses increment toward
					 * right */
				fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask1 =
				    mrc_lmasktable[ccx1 & 0xF];
				fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask2 =
				    mrc_rmasktable[(ccx2 - 1) & 0xF];
				prime = cg2_prskew(src.pos.x) >= cg2_prskew(ccx1);
			    }
			    /* src and dst addrs */
			    ma_top = (u_char *) cg2_ropwordaddr(fb, 0, src.pos.x, src.pos.y + yoff);
			    by = (u_char *) cg2_ropwordaddr(fb, 0, ccx1, dst.pos.y + yoff);
			    if (rop_isdown(dir)) {
				src.pos.y -= ccheight;
				dst.pos.y -= ccheight;
			    }
			    else {
				src.pos.y += ccheight;
				dst.pos.y += ccheight;
			    }
			    fb->status.reg.ropmode = PWRWRD;
			    if (w) {
				w--;	/* words to xfer minus two */
				if (rop_isright(dir))
				    while (--ccheight >= 0) {
					ma = ma_top;
					bx = by;
					if (prime)
					    cg2_setrsource(fb, CG2_ALLROP, *((short *) ma)--);
					*((short *) bx) = *((short *) ma);
					fb->status.reg.ropmode = ropmode;
					rop_fastloop(w, *--((short *) bx) = *--((short *) ma));
					fb->status.reg.ropmode = PWRWRD;
					*--((short *) bx) = *--((short *) ma);
					ma_top += linebytes;
					by += linebytes;
				    }
				else
				    while (--ccheight >= 0) {
					ma = ma_top;
					bx = by;
					if (prime)
					    cg2_setlsource(fb, CG2_ALLROP, *((short *) ma)++);
					*((short *) bx)++ = *((short *) ma)++;
					fb->status.reg.ropmode = ropmode;
					rop_fastloop(w, *((short *) bx)++ = *((short *) ma)++);
					fb->status.reg.ropmode = PWRWRD;
					*((short *) bx) = *((short *) ma);
					ma_top += linebytes;
					by += linebytes;
				    }
			    }
			    else {
				fb->status.reg.ropmode = PWRWRD;	/* ld dst for mask */
				ma = ma_top;
				bx = by;
				if (prime)
				    while (--ccheight >= 0) {
					cg2_setlsource(fb, CG2_ALLROP, *((short *) ma));
					*((short *) bx) = *(((short *) ma) + 1);
					ma += linebytes;
					bx += linebytes;
				    }
				else
				    while (--ccheight >= 0) {
					*((short *) bx) = *((short *) ma);
					ma += linebytes;
					bx += linebytes;
				    }
			    }
			}
		    }
		    else {
			short       srcx,
			            xlimit;
			if (src_pr->pr_ops != &mem_ops) {
			    /*
			     * Case 2c: Source is some other kind of
			     * pixrect, but not memory. Ask the other
			     * pixrect to read itself into temporary
			     * memory to make the problem easier. 
			     */
			    tem1.pr = mem_create(dst.size.x, dst.size.y, src.pr->pr_depth);
			    errs |= (*src_pr->pr_ops->pro_rop) (tem1.pr, 0, 0, dst.size.x, dst.size.y,
				  PIX_SRC, src.pr, src.pos.x, src.pos.y);
			    src.pr = src_pr = tem1.pr;
			    src.pos.x = src.pos.y = 0;
			    sdx = dst.pos.x;
			    sdy = dst.pos.y;
			}

			/*
			 * Case 2d: Source is a memory pixrect.  This case
			 * we can handle because the format of memory
			 * pixrects is public knowledge. 
			 */
			ma_vert = mpr_mdlinebytes(src_pr);
			linebytes = cg2_linebytes(fb, PWRWRD);
			srcx = src.pos.x;
			xlimit = dst.pos.x + dst.size.x;
			/*
			 * Case 2d.2: Source memory pixrect has width > 1
			 * || height > 1. We copy the source pixrect to
			 * the destination.  If the source pixrect depth =
			 * 1 the source value is zero or color. 
			 */
			if (src_pr->pr_depth == 1) {
			    short       ropmode,
			                prime,
			                nodst;
			    register short *mwa;

			    /*-				if (color == 0)
			    				    color = -1; */
			    switch (op) {
			    case (PIX_SRC | PIX_DST) >> 1:
				fb->ppmask.reg = color;
				cg2_setpattern(fb, CG2_ALLROP, ~0);
				fb->ppmask.reg = ~color;
				cg2_setpattern(fb, CG2_ALLROP, 0);
				fb->ppmask.reg = dbd->cgpr_planes;
				cg2_setfunction(fb, CG2_ALLROP,
				   CG_SRC & CG_MASK | ~CG_SRC & CG_DEST);
				break;
			    case (PIX_NOT(PIX_SRC) | PIX_DST) >> 1:
				fb->ppmask.reg = color;
				cg2_setpattern(fb, CG2_ALLROP, ~0);
				fb->ppmask.reg = ~color;
				cg2_setpattern(fb, CG2_ALLROP, 0);
				fb->ppmask.reg = dbd->cgpr_planes;
				cg2_setfunction(fb, CG2_ALLROP,
				   ~CG_SRC & CG_MASK | CG_SRC & CG_DEST);
				break;
			    case PIX_SRC >> 1:
				fb->ppmask.reg = color & magic_hack_bgcolor;
				cg2_setfunction(fb, CG2_ALLROP, ~0);
				fb->ppmask.reg = ~(color | magic_hack_bgcolor);
				cg2_setfunction(fb, CG2_ALLROP, 0);
				fb->ppmask.reg = color & ~magic_hack_bgcolor;
				cg2_setfunction(fb, CG2_ALLROP, CG_SRC);
				fb->ppmask.reg = ~color & magic_hack_bgcolor;
				cg2_setfunction(fb, CG2_ALLROP, ~CG_SRC);
				fb->ppmask.reg = dbd->cgpr_planes;
				break;
			    case PIX_NOT(PIX_DST) >> 1:
			    case (PIX_SRC ^ PIX_DST) >> 1:
				fb->ppmask.reg = 0xFF;
				cg2_setfunction(fb, CG2_ALLROP, CG_SRC ^ CG_DEST);
				break;
			    default:
				fb->ppmask.reg = color;
				fb->ropcontrol[CG2_ALLROP].ropregs.mrc_pattern = -1;
				fb->ppmask.reg = ~color;
				fb->ropcontrol[CG2_ALLROP].ropregs.mrc_pattern = 0;
				/* set op,planes */
				fb->ppmask.reg = dbd->cgpr_planes;
				cg2_setfunction(fb, CG2_ALLROP, op << 4);
			    }
			    nodst = 0;
			    if (nodst)
				ropmode = PRWWRD;	/* dont ld dst on wr */
			    else
				ropmode = PWWWRD;	/* always ld src on wr */
			    while (dst.size.y > 0) {
				short       x1 = dst.pos.x,
				            x2 = xlimit;
				register    height;
				trap.x1 += xoff;
				trap.x2 += xoff;
				if (trap.x1 > x1) {
				    src.pos.x = srcx + trap.x1 - x1;
				    x1 = trap.x1;
				}
				else
				    src.pos.x = srcx;
				if (trap.x2 < x2)
				    x2 = trap.x2;
#ifdef undef
				while (max(trap.next.x1, dst.pos.x) == x1
				       && min(trap.next.x2, xlimit) == x2 && trap.next.y < ylimit)
				    trap.next = *trap.seg++;
#else
				if (dst.pos.x == x1)
				    if (xlimit == x2)
					while (trap.next.x1 + xoff <= x1 && trap.next.x2 + xoff >= x2
					       && trap.next.y < ylimit)
					    trap.next = *trap.seg++;
				    else
					while (trap.next.x1 + xoff <= x1 && trap.next.x2 + xoff == x2
					       && trap.next.y < ylimit)
					    trap.next = *trap.seg++;
				else if (xlimit == x2)
				    while (trap.next.x1 + xoff == x1 && trap.next.x2 + xoff >= x2
					   && trap.next.y < ylimit)
					trap.next = *trap.seg++;
				else
				    while (trap.next.x1 + xoff == x1 && trap.next.x2 + xoff == x2
					   && trap.next.y < ylimit)
					trap.next = *trap.seg++;
#endif
				height = trap.next.y - trap.y;
				if (height <= 0)
				    break;
				if (height > dst.size.y)
				    height = dst.size.y;
				step_down_trap(&trap, height);
				if (x1 < x2) {
				    skew = mprs_skew(src);
				    ma_top = (u_char *) mprs_addr(src);
				    fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask1 =
					mrc_lmasktable[x1 & 0xF];
				    fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask2 =
					mrc_rmasktable[(x2 - 1) & 0xF];
				    w = cg2_prskew(x1);
				    cg2_setshift(fb, CG2_ALLROP, (w - skew) & 0xF, 1);
				    prime = (skew >= w);
				    w = (x2 - x1 + w - 1) >> 4;	/* set width,opcount */
				    cg2_setwidth(fb, CG2_ALLROP, w, w);
				    fb->status.reg.ropmode = PWWWRD;
				    by = (u_char *) cg2_ropwordaddr(fb, 0, x1, dst.pos.y + yoff);
				    src.pos.y += height;
				    dst.pos.y += height;
				    dst.size.y -= height;
				    switch (w) {
				    case 0:
					while (height--) {
					    mwa = (short *) ma_top;
					    if (prime)
						cg2_setrsource(fb, CG2_ALLROP, *mwa++);
					    *((short *) by) = *mwa;
					    by += linebytes;
					    (char *) ma_top += ma_vert;
					}
					break;
				    case 1:
					while (height--) {
					    mwa = (short *) ma_top;
					    bx = by;
					    if (prime)
						cg2_setrsource(fb, CG2_ALLROP, *mwa++);
					    *((short *) bx)++ = *mwa++;
					    *((short *) bx)++ = *mwa;
					    by += linebytes;
					    (char *) ma_top += ma_vert;
					}
					break;
				    default:
					if (nodst) {
					    w -= 2;
					    cg2_setwidth(fb, CG2_ALLROP, 2, 2);
					    while (height--) {
						mwa = (short *) ma_top;
						bx = by;
						if (prime)
						    cg2_setrsource(fb, CG2_ALLROP, *mwa++);
						*((short *) bx)++ = *mwa++;
						*((short *) bx)++ = *mwa++;
						fb->status.reg.ropmode = ropmode;
						rop_fastloop(w, *((short *) bx)++ = *mwa++);
						fb->status.reg.ropmode = PWWWRD;
						*((short *) bx)++ = *mwa;
						by += linebytes;
						(char *) ma_top += ma_vert;
					    }
					}
					else {
					    while (height--) {
						mwa = (short *) ma_top;
						bx = by;
						if (prime)
						    cg2_setrsource(fb, CG2_ALLROP, *mwa++);
						rop_fastloop(w, *((short *) bx)++ = *mwa++);
						*((short *) bx)++ = *mwa;
						by += linebytes;
						(char *) ma_top += ma_vert;
					    }
					}
				    }
				}
				else {
				    src.pos.y += height;
				    dst.pos.y += height;
				    dst.size.y -= height;
				}
			    }
			}
			else if (src_pr->pr_depth == 8) {
			    return generic_shaperop(dst_pr, shape, OP,
						    src_pr, sdx, sdy);
#ifdef undef
			    /*
			     * a raster line of byte pixels is padded to
			     * word boundaries so that two pixel transfers
			     * to the hardware can be done with word
			     * moves.  The ROPC masks will trim the odd
			     * pixels off the ends. 
			     */
			    fb->ppmask.reg = dbd->cgpr_planes;
			    cg2_setfunction(fb, CG2_ALLROP, op);
			    fb->ropcontrol[CG2_ALLROP].ropregs.mrc_pattern = 0;
			    trap.x1 += xoff;
			    trap.x2 += xoff;
			    while (--dst.size.y >= 0) {
				short       x1 = dst.pos.x,
				            x2 = xlimit;
				if (trap.x1 > x1) {
				    src.pos.x = srcx + trap.x1 - x1;
				    x1 = trap.x1;
				}
				else
				    src.pos.x = srcx;
				if (trap.x2 < x2)
				    x2 = trap.x2;
				trap.y++;
				while (trap.y >= trap.next.y && trap.seg <= trap.limit) {
				    trap.x1 = trap.next.x1 + xoff;
				    trap.x2 = trap.next.x2 + xoff;
				    trap.next = *trap.seg++;
				}
				if (x1 < x2) {
				    ma_top = mprs8_addr(src);
				    by = (u_char *) cg2_roppixaddr(fb, x1, trap.y + yoff - 1);
				    (int) ma = ((int) ma_top & 1);
				    (int) bx = ((int) by & 1);
				    if (ma == bx) {
					w = x2 - x1 + (int) ma;
					w = ((w + (w & 1)) >> 1) - 1;	/* wrds per raster line
									 * -1 */
					cg2_setshift(fb, CG2_ALLROP, 0, 1);
					cg2_setwidth(fb, CG2_ALLROP, w, w);

					fb->status.reg.ropmode = SWWPIX;
					linebytes = cg2_linebytes(fb, SWWPIX);

					fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask1 =
					    mrc_lmasktable[x1 & 0xF];
					fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask2 =
					    mrc_rmasktable[(x2 - 1) & 0xF];

					ma_top = (u_char *) ((int) ma_top & ~1);	/* word pad */
					by = (u_char *) ((int) by & ~1);	/* word pad */
					ma = ma_top;
					bx = by;
					fb->ropcontrol[CG2_ALLROP].prime.ropregs.
					    mrc_source1 = *((short *) ma)++;	/* prime fifo */
					rop_fastloop(w, *((short *) bx)++ = *((short *) ma)++);
					*((short *) bx)++ = w;	/* flush fifo */
				    }
				    else {
					w = x2 - x1 - 1;
					/* set op,color,planes */
					fb->ppmask.reg = dbd->cgpr_planes;
					cg2_setfunction(fb, CG2_ALLROP, op);
					fb->ropcontrol[CG2_ALLROP].ropregs.mrc_pattern = 0;
					cg2_setshift(fb, CG2_ALLROP, 0, 1);
					cg2_setwidth(fb, CG2_ALLROP, 0, 0);
					fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask1 = 0;
					fb->ropcontrol[CG2_ALLROP].ropregs.mrc_mask2 = 0;

					if (PIXOP_NEEDS_DST(op << 1))
					    fb->status.reg.ropmode = SWWPIX;
					else
					    fb->status.reg.ropmode = SRWPIX;
					linebytes = cg2_linebytes(fb, SWWPIX);

					ma = ma_top;
					bx = by;
					fb->ropcontrol[CG2_ALLROP].prime.ropregs.
					    mrc_source1 = *ma | (*ma << 8);	/* prime fifo */
					ma++;
					rop_fastloop(w, *bx++ = *ma++);
					*bx++ = w;	/* flush fifo */
				    }
				}
				src.pos.y++;
				dst.pos.y++;
			    }
#endif
			}
		    }
		}
	    }
	    /*
	     * Finish off 2c cases by discarding temporary memory pixrect. 
	     */
	}
Continue:
	if (!shape->is_rect && shape->trapset->next) {
	    nextshape = *shape;
	    nextshape.trapset = nextshape.trapset->next;
	    shape = &nextshape;
	}
	else {
	    if (tem1.pr)
		mem_destroy(tem1.pr);
	    return (errs);
	}
    }
}

#ifdef undef
cg2_rop(dpr, dx, dy, dw, dh, op, spr, sx, sy)
    struct pixrect *dpr, *spr;
{
    struct shape shape;
    shape.is_rect = 1;
    shape.pos.x = dx;
    shape.pos.y = dy;
    shape.size.x = dw;
    shape.size.y = dh;
    cg2_shaperop(dpr, &shape, op, spr, dx - sx, dy - sy);
}

#endif