/*
 * Acceleration for the Creator and Creator3D framebuffer - Non-filled rects.
 *
 * Copyright (C) 1999 David S. Miller (davem@redhat.com)
 * Copyright (C) 1999 Jakub Jelinek   (jakub@redhat.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * DAVID MILLER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sunffb/ffb_rect.c,v 1.1 2000/05/18 23:21:37 dawes Exp $ */

#define PSZ 32

#include "ffb.h"
#include "ffb_regs.h"
#include "ffb_rcache.h"
#include "ffb_fifo.h"
#include "ffb_loops.h"
#include "ffb_clip.h"

#include "pixmapstr.h"
#include "scrnintstr.h"

#include "cfb.h"

#error If we start using this again, need to fixup FFB_WRITE_ATTRIBUTES for wids -DaveM

/* Heavily derived from mipolyrect.c code, see there for authors. */

/* This about it, capping makes not a single difference ever,
 * always the upper left corner coordinate will be pixelated.
 */
void
CreatorPolyRectangle(DrawablePtr pDrawable, GCPtr pGC,
		     int nrects, xRectangle *pRects)
{
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pDrawable->pScreen);
	CreatorPrivGCPtr gcPriv = CreatorGetGCPrivate (pGC);
	ffb_fbcPtr ffb = pFfb->regs;
	xRectangle *pR = pRects;
	RegionPtr clip;
	unsigned int ppc, line_drawop;
	int bound_tmp, i, numRects;

	if(nrects <= 0)
		return;
	clip = ((cfbPrivGC *)(pGC->devPrivates[cfbGCPrivateIndex].ptr))->pCompositeClip;
	numRects = REGION_NUM_RECTS(clip);
	if (!numRects)
		return;
	if(!(ppc = FFBSetClip(pFfb, ffb, clip, numRects))) {
		miPolyRectangle(pDrawable, pGC, nrects, pRects);
		return;
	}
	if(pGC->lineStyle == LineDoubleDash)
		line_drawop = FFB_DRAWOP_DDLINE;
	else
		line_drawop = FFB_DRAWOP_BRLINECAP;
	if(gcPriv->stipple == NULL) {
		FFB_WRITE_ATTRIBUTES(pFfb,
				     ppc|FFB_PPC_APE_DISABLE|FFB_PPC_TBE_OPAQUE|
				     FFB_PPC_XS_CONST|FFB_PPC_YS_CONST|FFB_PPC_ZS_CONST|FFB_PPC_CS_CONST,
				     FFB_PPC_VCE_MASK|FFB_PPC_ACE_MASK|FFB_PPC_APE_MASK|FFB_PPC_TBE_MASK|
				     FFB_PPC_XS_MASK|FFB_PPC_YS_MASK|FFB_PPC_ZS_MASK|FFB_PPC_CS_MASK,
				     pGC->planemask,
				     FFB_ROP_EDIT_BIT|pGC->alu,
				     -1, pGC->fgPixel,
				     FFB_FBC_DEFAULT);
		if(pGC->lineStyle == LineDoubleDash)
			FFB_WRITE_BG(pFfb, ffb, pGC->bgPixel);
	} else {
		FFBSetStipple(pFfb, ffb, gcPriv->stipple,
			      ppc|
			      FFB_PPC_XS_CONST|FFB_PPC_YS_CONST|FFB_PPC_ZS_CONST|FFB_PPC_CS_CONST,
			      FFB_PPC_VCE_MASK|FFB_PPC_ACE_MASK|
			      FFB_PPC_XS_MASK|FFB_PPC_YS_MASK|FFB_PPC_ZS_MASK|FFB_PPC_CS_MASK);
		FFB_WRITE_PMASK(pFfb, ffb, pGC->planemask);
		FFB_WRITE_FBC(pFfb, ffb, FFB_FBC_DEFAULT);
	}

#define MINBOUND(dst,eqn)	bound_tmp = eqn; \
				if (bound_tmp < -32768) \
				    bound_tmp = -32768; \
				dst = bound_tmp;

#define MAXBOUND(dst,eqn)	bound_tmp = eqn; \
				if (bound_tmp > 32767) \
				    bound_tmp = 32767; \
				dst = bound_tmp;

#define MAXUBOUND(dst,eqn)	bound_tmp = eqn; \
				if (bound_tmp > 65535) \
				    bound_tmp = 65535; \
				dst = bound_tmp;

	if (pGC->lineStyle == LineSolid &&
	    pGC->joinStyle == JoinMiter &&
	    pGC->lineWidth != 0) {
		int ntmp;
		int offset1, offset2, offset3;
		int x, y, width, height;
		int tx, ty, tw, th;

		ntmp = (nrects << 2);
		offset2 = pGC->lineWidth;
		offset1 = offset2 >> 1;
		offset3 = offset2 - offset1;
		for (i = 0; i < nrects; i++) {
			x = pR->x;
			y = pR->y;
			width = pR->width;
			height = pR->height;
			pR++;
			if (width == 0 && height == 0) {
				FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_DOT);
				FFBFifo(pFfb, 2);
				FFB_WRITE64(&ffb->bh, y + pDrawable->y, x + pDrawable->x);
				continue;
			}
			FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
			if (height < offset2 || width < offset1) {
				if (height == 0) {
					tx = x;
					tw = width;
				} else {
					MINBOUND (tx, x - offset1);
					MAXUBOUND (tw, width + offset2);
				}
				if (width == 0) {
					ty = y;
					th = height;
				} else {
					MINBOUND (ty, y - offset1);
					MAXUBOUND (th, height + offset2);
				}
				FFBFifo(pFfb, 4);
				FFB_WRITE64(&ffb->by, ty + pDrawable->y, tx + pDrawable->x);
				FFB_WRITE64_2(&ffb->bh, th, tw);
			} else {
				MINBOUND(tx, x - offset1);
				MINBOUND(ty, y - offset1);
				MAXUBOUND(tw, width + offset2);
				th = offset2;
				FFBFifo(pFfb, 13);
				FFB_WRITE64(&ffb->by, ty + pDrawable->y, tx + pDrawable->x);
				FFB_WRITE64_2(&ffb->bh, th, tw);
				MAXBOUND(ty, y + offset3);
				tw = offset2;
				th = height - offset2;
				ffb->by = ty + pDrawable->y;
				FFB_WRITE64_2(&ffb->bh, th, tw);
				MAXBOUND(tx, x + width - offset1);
				ffb->bx = tx + pDrawable->x;
				ffb->bw = tw;				
				MINBOUND(tx, x - offset1);
				MAXBOUND(ty, y + height - offset1);
				MAXUBOUND(tw, width + offset2);
				th = offset2;
				FFB_WRITE64(&ffb->by, ty + pDrawable->y, tx + pDrawable->x);
				FFB_WRITE64_2(&ffb->bh, th, tw);
			}
		}
	} else {
		int xOrg = pDrawable->x;
		int yOrg = pDrawable->y;
		unsigned int linepat = gcPriv->linepat;

		FFB_WRITE_DRAWOP(pFfb, ffb, line_drawop);
		if(linepat == 0) {
			FFBFifo(pFfb, 1);
			ffb->lpat = 0;
		}
		for (i=0; i < nrects; i++) {
			register int x0, xCoord, y0, yCoord;

			x0 = xCoord = pR->x;
			y0 = yCoord = pR->y;
			FFBFifo(pFfb, 11);
			if(linepat)
				ffb->lpat = linepat;
			else
				ffb->ppc = 0;
			FFB_WRITE64(&ffb->by, (yCoord + yOrg), (xCoord + xOrg));
			MAXBOUND(xCoord, pR->x + (int) pR->width);
			FFB_WRITE64(&ffb->bh, (yCoord + yOrg), (xCoord + xOrg));
			MAXBOUND(yCoord, pR->y + (int) pR->height);
			FFB_WRITE64_2(&ffb->bh, (yCoord + yOrg), (xCoord + xOrg));
			FFB_WRITE64_3(&ffb->bh, (yCoord + yOrg), (x0 + xOrg));
			FFB_WRITE64(&ffb->bh, (y0 + yOrg), (x0 + xOrg));
			pR++;
		}
	}
}
