/* $XConsortium: offscreen.c,v 1.2 94/10/12 21:06:18 kaleb Exp $ */
/* $XFree86: xc/programs/Xserver/hw/xfree86/vga16/ibm/offscreen.c,v 3.1 1994/06/18 16:26:33 dawes Exp $ */
/*
 * Copyright 1993 Gerrit Jan Akkerman 
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that 
 * both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of Gerrit Jan Akkerman not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * GERRIT JAN AKKERMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL GERRIT JAN AKKERMAN BE LIABLE FOR ANY SPECIAL, INDIRECT
 * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
*/
/*
 * Copyright IBM Corporation 1987,1988,1989
 *
 * All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that 
 * both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of IBM not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
*/

#include "X.h"
#include "compiler.h"
#include "vgaVideo.h"

#include "windowstr.h" /* GJA -- for pWin */
#include "scrnintstr.h" /* GJA -- for pWin */
#include "pixmapstr.h" /* GJA -- for pWin */
#include "ppc.h" /* GJA -- for pWin */

unsigned char *saved_screen;

#define SAVEDSCREEN(pWin, x, y) \
	(*(saved_screen + (y) * (BYTES_PER_LINE(pWin) << 3) + (x)))

#define DO_ROP(src,dst,alu,planes) \
	((dst) = do_rop((src),(dst),(alu),(planes)))

/* NOTE:
 * The following to functions don't do anything. They're just there to
 * provide a stable interface to the rest of the system.
 */

/* Save the screen pixels, and stow away a pointer to their data in
 * saved_screen.
 */
vgaSaveScreenPix(pScreen,ppix)
PixmapPtr ppix;
ScreenPtr pScreen;
{
          vgaReadColorImage( (WindowPtr)(pScreen->devPrivate),
			0,0,pScreen->width,pScreen->height,
                        ppix->devPrivate.ptr,ppix->devKind);
          saved_screen = ppix->devPrivate.ptr;
}

/* Restore the screen pixels
 */
vgaRestoreScreenPix(pScreen,ppix)
PixmapPtr ppix;
ScreenPtr pScreen;
{
          vgaDrawColorImage( (WindowPtr)(pScreen->devPrivate),
			0,0,pScreen->width,pScreen->height,
                        ppix->devPrivate.ptr,ppix->devKind,GXcopy,0x0F);

}

int do_rop(src,dst,alu,planes)
int src,dst,alu;
const unsigned long planes;
{ 
	int _dst;	/* New dst */

	switch ( alu ) { 
		case GXclear:		/* 0x0 Zero 0 */ 
			_dst = 0; break ; 
		case GXinvert:		/* 0xa NOT dst */ 
			_dst = ~dst; break ; 
		case GXset:		/* 0xf 1 */ 
			_dst = src; break ; 
		case GXnoop:		/* 0x5 dst */ 
			return dst; 
		case GXnor:		/* 0x8 NOT src AND NOT dst */ 
			_dst = ~src & ~dst; break ; 
		case GXandInverted:	/* 0x4 NOT src AND dst */ 
			_dst = ~src & dst; break ; 
		case GXand:		/* 0x1 src AND dst */ 
			_dst = src & dst; break ; 
		case GXequiv:		/* 0x9 NOT src XOR dst */ 
			_dst = ~src ^ dst; break ; 
		case GXxor:		/* 0x6 src XOR dst */ 
			_dst = src ^ dst; break ; 
		case GXandReverse:	/* 0x2 src AND NOT dst */ 
			_dst = src & ~dst; break ; 
		case GXnand:		/* 0xe NOT src OR NOT dst */ 
			_dst = ~src | ~dst; break ; 
		case GXorReverse:	/* 0xb src OR NOT dst */ 
			_dst = src | ~dst; break ; 
		case GXorInverted:	/* 0xd NOT src OR dst */ 
			_dst = ~src | dst; break ; 
		case GXor:		/* 0x7 src OR dst */ 
			_dst = src | dst; break ; 
		case GXcopyInverted:	/* 0xc NOT src */ 
			_dst = ~src; break ; 
		case GXcopy:		/* 0x3 src */ 
			_dst = src; break ; 
		default: 
			break ; 
	} 
	return (dst & ~planes) | (_dst & planes); 
}

/* File vgaBitBlt.c */
void
offBitBlt( pWin, alu, readplanes, writeplanes, x0, y0, x1, y1, w, h )
WindowPtr pWin; /* GJA */
const int alu, readplanes, writeplanes ;
register int x0 ;
int y0 ;
register int x1 ;
int y1 ;
register int w, h ;
{
	int x,y,tmp1,tmp2;

	switch ( alu ) {
		case GXclear:		/* 0x0 Zero 0 */
		case GXinvert:		/* 0xa NOT dst */
		case GXset:		/* 0xf 1 */
			offFillSolid( pWin, VGA_ALLPLANES, alu, writeplanes,
				x0, y0, w, h ) ;
		case GXnoop:		/* 0x5 dst */
			return ;
		default:
			break ;
	}

	if ( (w <= 0) || (h <= 0) ) return;

	for ( y = 0 ; y < h ; y++ ) {
		for ( x = 0 ; x < w ; x++ ) {
			DO_ROP(SAVEDSCREEN(pWin,x0+x,y0+y),SAVEDSCREEN(pWin,x1+x,y1+y),
				alu,writeplanes);
		}
	}
}

/* for file vgaImages.c */

void
offDrawColorImage( pWin, x, y, w, h, data, RowIncrement, alu, planes )
WindowPtr pWin; /* GJA */
int x, y ;
register int w, h ;
unsigned char *data ;
register int RowIncrement ;
const int alu ;
const unsigned long int planes ;
{
	int dx,dy;
	int src, dst;

	for ( dy = 0 ; dy < h ; dy++ ) {
		for ( dx = 0 ; dx < w ; dx++ ) {
			DO_ROP(	data[dy * RowIncrement + dx],
				SAVEDSCREEN(pWin,x+dx,y+dy), alu, planes);
		}
	}
}

void
offReadColorImage( pWin, x, y, lx, ly, data, RowIncrement )
WindowPtr pWin; /* GJA */
int x, y ;
int lx, ly ;
unsigned char *data ;
int RowIncrement ;
{
	int dx, dy;

	if ( ( lx <= 0 ) || ( ly <= 0 ) )
		return ;

	for ( dy = 0 ; dy < ly ; dy++ ) {
		for ( dx = 0 ; dx < lx ; dx++ ) {
			data[dy*RowIncrement+dx] = SAVEDSCREEN(pWin,x+dx,y+dy);
		}
	}
}

/* for file vgaLine.c */

/* X increasing */
static void fast_x_line_right( et, e1, e2, len, y_increment, addr, alu, color,
	planes )
register int et ;
const int e1 ;
const int e2 ;
unsigned int len ;
const int y_increment ;
register unsigned volatile char *addr ;
const int alu, color, planes ;
{

	while ( len ) {
		DO_ROP(color, *addr, alu, planes);
		if ( et < 0 ) {
			et += e1 ;
		}
		else {
			et += e2 ;
			addr += y_increment ;
		}
		addr++;
		len--;
	}
}

/* X decreasing */
static void fast_x_line_left( et, e1, e2, len, y_increment, addr, alu, color,
	planes )
register int et ;
const int e1 ;
const int e2 ;
unsigned int len ;
const int y_increment ;
register unsigned volatile char *addr ;
const int alu, color, planes ;
{

	while ( len ) {	
		DO_ROP(color, *addr, alu, planes);
		if ( et < 0 ) {
			et += e1 ;
		}
		else {
			et += e2 ;
			addr += y_increment ;
		}
		addr--;
		len--;
	}
}

/* X increasing */
static void fast_y_line_right( et, e1, e2, len, y_increment, addr, alu, color,
	planes )
register int et ;
const int e1 ;
const int e2 ;
unsigned int len ;
const int y_increment ;
register unsigned volatile char *addr ;
const int alu, color, planes ;
{

	while ( len ) {
		DO_ROP(color, *addr, alu, planes);
		addr += y_increment ;
		if ( et < 0 ) {
			et += e1 ;
		} else {
			et += e2 ;
			addr++;
		}
		len--;
	}
}


/* X decreasing */
static void fast_y_line_left( et, e1, e2, len, y_increment, addr, alu, color,
	planes )
register int et ;
const int e1 ;
const int e2 ;
unsigned int len ;
const int y_increment ;
register unsigned volatile char *addr ;
const int alu, color, planes ;
{
	while ( len ) {
		DO_ROP(color, *addr, alu, planes);
		addr += y_increment ;
		if ( et < 0 ) {
			et += e1 ;
		} else {
			et += e2 ;
			addr--;
		}
		len--;
	}
}

void offBresLine( pWin, color, alu, planes, signdx, signdy,
		  axis, x, y, et, e1, e2, len )
WindowPtr pWin; /* GJA */
unsigned long int color ;
int alu ;
unsigned long int planes ;
int signdx, signdy ;
int axis, x, y ;
int et, e1, e2 ;
unsigned long int len ;
{
if ( !( planes & VGA_ALLPLANES ) ) {
	return ;
} else if ( len == 1 ) {
	offFillSolid( pWin, color, alu, planes, x, y, 1, 1 ) ;
	return ;
}

/* Call the real workers */
(* ( ( signdx > 0 ) ? ( axis ? fast_y_line_right : fast_x_line_right )
		    : ( axis ? fast_y_line_left  : fast_x_line_left ) ) )
			( et, e1, e2, (unsigned int)len,
			  ( signdy > 0 ?   (BYTES_PER_LINE(pWin)<<3)
				       : - (BYTES_PER_LINE(pWin)<<3) ),
			  &SAVEDSCREEN( pWin, x, y ), alu,
			  (const int)color, (const int)planes ) ;

return ;
}

/* For file vgaSolid.c */

void offFillSolid( pWin, color, alu, planes, x0, y0, lx, ly )
WindowPtr pWin; /* GJA */
unsigned long int color ;
const int alu ;
unsigned long int planes ;
register int x0 ;
register const int y0 ;
register int lx ;
register const int ly ;		/* MUST BE > 0 !! */
{
	int dx, dy;

	if ( ( lx == 0 ) || ( ly == 0 ) )
		return;

	for ( dy = 0 ; dy < ly ; dy++ ) {
		for ( dx = 0 ; dx < lx ; dx++ ) {
			DO_ROP(color,SAVEDSCREEN(pWin, x0+dx,y0+dy),alu,planes);
		}
	}
}
	
/* For file vgaStipple.c */

/* GJA -- modified this to take both Width and Height, and to
 * reduce x and y to Width and Height by taking remainders.
 */
static unsigned char
xygetbits( x, y, Width, paddedByteWidth, Height, data )
register int x,y ;
register const unsigned int Width, paddedByteWidth, Height ;
register const unsigned char * const data ;
{
	register unsigned char bits ;
	unsigned const char *lineptr, *cptr ;
	register shift ;
	register wrap ;

	x = x % Width;
	y = y % Height;

	lineptr = data + (y * paddedByteWidth);
	cptr = lineptr + (x >> 3) ;
	bits = *cptr ;
	if ( shift = x & 7 )
		bits = SCRLEFT8( bits, shift ) |
			SCRRIGHT8( cptr[1], ( 8 - shift ) ) ;
	if ( ( wrap = x + 8 - Width ) > 0 ) {
		bits &= SCRLEFT8( 0xFF, wrap ) ;
		bits |= SCRRIGHT8( *lineptr, ( 8 - wrap ) ) ;
	}

	return bits ;
}

static void
DoMono( pWin, w, x, y, mastersrc, h, width, paddedByteWidth, height,
	      xshift, yshift, alu, planes, fg )
WindowPtr pWin; /* GJA */
int x, y ;
register const unsigned char *mastersrc ;
int w, h ;			/* width and height of area to be stippled */
unsigned int width, height ;	/* width and height of stipple */
register unsigned int paddedByteWidth;
int xshift ;
int yshift ;
int alu, planes, fg;
{
	int dy, dx, i;
	int byte;
	int color;

	for ( dy = 0 ; dy < h ; dy++ ) {
		for ( dx = 0; dx <= w - 8 ; dx += 8 ) {
			/* get next byte */
			byte = xygetbits(dx+xshift,dy+yshift,width,
					paddedByteWidth, height, mastersrc);
			for ( i = 0 ; i < 8 ; i++ ) {
				if ( byte & (128 >> i) ) {
					DO_ROP(fg,SAVEDSCREEN(pWin,x+dx+i,y+dy),
						alu,planes);
				}
			}
		}
		/* get last bits */
		byte = xygetbits(dx+xshift,dy+yshift,width,
				paddedByteWidth, height, mastersrc);
		for ( i = 0 ; i < (w - dx) ; i++ ) {
			if ( byte & (128 >> i) ) {
				DO_ROP(fg,SAVEDSCREEN(pWin,x+dx+i,y+dy),
					alu,planes);
			}
		}
	}
}

void
offDrawMonoImage( pWin, data, x, y, w, h, fg, alu, planes )
WindowPtr pWin; /* GJA */
unsigned char *data;
int x, y, w, h ;
unsigned long int fg ;
int alu ;
unsigned long int planes;
{

	if ( ( alu == GXnoop ) || !( planes &= VGA_ALLPLANES ) )
		return ;

	DoMono( pWin, w, x, y, (const unsigned char *) data, h,
		      w, ( ( w + 31 ) & ~31 ) >> 3, h, 0, 0, alu,
		      (int)planes, (int)fg) ;

}

void
offFillStipple( pWin, pStipple, fg, alu, planes, x, y, w, h, xSrc, ySrc )
WindowPtr pWin; /* GJA */
register PixmapPtr const pStipple ;
unsigned long int fg ;
const int alu ;
unsigned long int planes ;
int x, y, w, h ;
const int xSrc, ySrc ;
{
	unsigned int width ;
	unsigned int height ;
	int xshift ;
	int yshift ;

	if ( ( alu == GXnoop ) || !( planes &= VGA_ALLPLANES ) )
		return ;

	/* Figure Bit Offsets & Source Address */
	width = pStipple->drawable.width ;
	if ( ( xshift = ( x - xSrc ) ) < 0 )
		xshift = width - ( ( - xshift ) % width ) ;
	else
		xshift %= width ;

	height = pStipple->drawable.height ;
	if ( ( yshift = ( y - ySrc ) ) < 0 )
		yshift = height - ( ( - yshift ) % height ) ;
	else
		yshift %= height ;

	DoMono( pWin, w, x, y,
		(const unsigned char *) pStipple->devPrivate.ptr,
		h,
		width,
		( ( width + 31 ) & ~31 ) >> 3,
		height,
		xshift, yshift,
		alu, (int)planes, (int)fg ) ;
	return ;
}
