#ifndef lint
static char	sccsid[] = "@(#)pixels2.c 1.1 94/10/31 Copyr 1985-9 Sun Micro";
#endif

/*
 * Copyright (c) 1985, 1986, 1987, 1988, 1989 by Sun Microsystems, Inc. 
 * Permission to use, copy, modify, and distribute this software 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 are retained, and that the name 
 * of Sun Microsystems, Inc., not be used in advertising or publicity 
 * pertaining to this software without specific, written prior permission. 
 * Sun Microsystems, Inc., makes no representations about the suitability 
 * of this software or the interface defined in this software for any 
 * purpose. It is provided "as is" without express or implied warranty.
 */
/*
 * CGI Bitblt Output Primitives
 */

/*
bitblt_source_array
bitblt_pattern_array
bitblt_patterned_source_array 
set_global_drawing_mode 
set_drawing_mode 
inquire_drawing_mode 
inquire_device_bitmap 
inquire_bitblt_alignments 
*/

#include "cgipriv.h"		/* defines types used in this file  */
#include <pixrect/pixrect_hs.h>

#ifdef	i386
#define	UCHAR_MSB	0x01
#else	!i386
#define	UCHAR_MSB	0x80
#endif	i386

int             _cgi_pix_mode;	/* pixrect equivalent of drawing mode */
int             _cgi_background_color;	/* background color (no longer used) */
View_surface   *_cgi_vws;	/* current view surface */

Ccombtype _cgi_drawing_mode;
int             _cgi_pix_drawing_mode;
Ccombtype _cgi_bit_drawing_mode;
Cbmode _cgi_bit_vis_mode;
Cbitmaptype _cgi_bit_source;
Cbitmaptype _cgi_bit_dest;


/****************************************************************************/
/*                                                                          */
/*     FUNCTION: bitblt_source_array 					    */
/*                                                                          */
/*	DOES:	Read off screen the rectangle defined by (xo,yo),(xe,ye)    */
/*		Read it into the pixwin provided by bitsource at (0,0)      */
/*		Depending on drawing mode, perform an OP on user's bitsource*/
/*		Using _cgi_pix_mode, ROP bitsource onto			    */
/*		_cgi_vws->sunview.pw at xt,yt				    */
/*		Read result (at xt,yt) into raster array bittarget at (0,0) */
/*                                                                          */
/*	COULD:	Move area in raster array bitsource			    */
/*		defined by (xo,yo),(xe,ye)				    */
/*		to raster array bittarget, positioned at (xt,yt)	    */
/****************************************************************************/

Cerror          bitblt_source_array(bitsource, xo, yo, xe, ye, bittarget, xt, yt, name)
Cpixrect       *bitsource, *bittarget;	/* source and target bitmaps */
Cint            xo, yo, xe, ye, xt, yt;	/* coordinates of source and target
					 * bitmaps */
/* Note: xe,ye (extents) are in screen space; other coordinates in VDC space */
Cint            name;
{
    int             err;
    int             height, width, x, x1, y, y1;

    err = _cgi_err_check_4();
    if (!err)
    {
	_cgi_devscale(xt, yt, x1, y1);	/* target */
	_cgi_devscale(xo, yo, x, y);	/* source */
	width = xe;		/* x and y extent */
	height = ye;
	err = _cgi_err_check_69(x1, y1);
	if (!err)
	    err = _cgi_err_check_69(x, y);
	if (!err)
	    err = _cgi_err_check_69(xe, ye);
	if (!err)
	{
	    err = _cgi_context(name);
	    if (!err)
	    {
		/*
		 * We'll read into the user's pixrects, which will need to
		 * already be allocated, even if the user isn't interested. 
		 */

		pw_read(bitsource, 0, 0, width, height, PIX_SRC,
			_cgi_vws->sunview.pw, x, y);
		pw_read(bittarget, 0, 0, width, height, PIX_SRC,
			_cgi_vws->sunview.pw, x1, y1);
		if (_cgi_bit_vis_mode == TRANSPARENT)
		{
		    Pixrect        *mprect1;

		    /* Transparent: use a stencil based on the source pixrect */
		    if (_cgi_vws->sunview.depth != 1)
		    {
			mprect1 = mem_create(xe, ye, 1);
			(void) _cgi_make_1_deep(mprect1, bitsource, xe, ye);
		    }
		    else
			mprect1 = bitsource;
		    /* Stencil: where source was zero, do not change dest */
		    pw_stencil(_cgi_vws->sunview.pw, x1, y1, xe, ye,
		       _cgi_pix_drawing_mode, mprect1, 0, 0, bitsource, 0, 0);
		    if (mprect1 != bitsource)
			(void) pr_destroy(mprect1);	/* no longer need
							 * pixrect */
		}
		else
		{
		    pw_write(_cgi_vws->sunview.pw, x1, y1, xe, ye,
			     _cgi_pix_drawing_mode, bitsource, 0, 0);
		}

		pw_read(bittarget, 0, 0, width, height, PIX_SRC,
			_cgi_vws->sunview.pw, x1, y1);
	    }
	}
    }
    return (_cgi_errhand(err));
}

/****************************************************************************/
/*                                                                          */
/*     FUNCTION: bitblt_pattern_array 					    */
/*                                                                          */
/*	DOES:	The above is performed.	 And also:			    */
/*		Read result (at xt,yt) into raster array pixtarget (to 0,0) */
/*                                                                          */
/*	COULD:	ROP onto a subregion (raster array) at (xo,yo) size (xe,ye) */
/*		a replicated pattern of size (px,py) given by pixpat 	    */
/****************************************************************************/

Cerror          bitblt_pattern_array
                (pixpat, px, py, pixtarget, rx, ry, ox, oy, dx, dy, name)
Cpixrect       *pixpat;		/* pattern source array */
Cint            px, py;		/* pattern extent */
Cpixrect       *pixtarget;	/* destination pattern array */
Cint            rx, ry;		/* pattern reference point */
Cint            ox, oy;		/* destination origin in VDC */
Cint            dx, dy;		/* destination extent */
Cint            name;		/* viewsurface name */
{
    int             err, x, y;

    err = _cgi_err_check_4();
    if (!pixpat)
	err = EPXNOTCR;
    if (!err)
    {
	_cgi_devscale(ox, oy, x, y);
	err = _cgi_err_check_69(x, y);
	if (!err)
	    err = _cgi_err_check_69(x + dx, y + dy);
	if (!err)
	{
	    err = _cgi_context(name);
	    if (!err)
	    {
		Pixrect        *repl_source;	/* Gets source for stencil */

		pw_read(pixtarget, 0, 0, dx, dy, PIX_SRC,
			_cgi_vws->sunview.pw, x, y);
		if (_cgi_bit_vis_mode == TRANSPARENT)
		{
		    Pixrect        *repl_stencil;	/* Gets (1-deep) stencil */
		    repl_stencil = mem_create(dx, dy, 1);	/* Full size, 1-bit */
		    /* Transparent: use a stencil based on the source pixrect */
		    if (pixpat->pr_depth != 1)
		    {
			Pixrect        *mprect1;	/* 1-bit deep pattern
							 * tile */
			mprect1 = mem_create(px, py, 1);
			(void) _cgi_make_1_deep(mprect1, pixpat, px, py);
			/* replicate 1-bit tile to 1-bit stencil */
			(void) pr_replrop(repl_stencil, 0, 0, dx, dy, PIX_SRC,
					  mprect1, rx % px, ry % py);
			(void) pr_destroy(mprect1);	/* no longer need
							 * pixrect */
			repl_source = mem_create(dx, dy,
						 _cgi_vws->sunview.depth);
			(void) pr_replrop(repl_source, 0, 0, dx, dy, PIX_SRC,
					  pixpat, rx % px, ry % py);
		    }
		    else
		    {
			(void) pr_replrop(repl_stencil, 0, 0, dx, dy, PIX_SRC,
					  pixpat, rx % px, ry % py);
			repl_source = repl_stencil;
		    }
		    /* Stencil: where source was zero, do not change dest */
		    pw_stencil(_cgi_vws->sunview.pw, x, y, dx, dy,
			       _cgi_pix_drawing_mode, repl_stencil,
			       0, 0, repl_source, 0, 0);
		    (void) pr_destroy(repl_stencil);	/* no longer need
							 * stencil */
		    (void) pr_destroy(repl_source);	/* no longer need source */
		}
		else
		{
		    pw_replrop(_cgi_vws->sunview.pw, x, y, dx, dy,
			     _cgi_pix_drawing_mode, pixpat, rx % px, ry % py);
		}
		/* We'll use the user's pixrects.  S/He'll have to allocate */
		pw_read(pixtarget, 0, 0, dx, dy, PIX_SRC,
			_cgi_vws->sunview.pw, x, y);
	    }
	}
    }
    return (_cgi_errhand(err));
}

/****************************************************************************/
/*                                                                          */
/*     FUNCTION: bitblt_patterned_source_array 				    */
/*                                                                          */
/*	DOES:	Replicate pixpat tile into size of extent (dx,dy) mprect2.  */
/*		Stencil source area (at sx,sy) of screen through pattern.   */
/*		Depending on drawing mode, perform an OP on the result.     */
/*		Read result (of mask and OP) into user's pixsource (at 0,0).*/
/*		COPY pixsource onto _cgi_vws->sunview.pw at (xt,yt).	    */
/*		Read result (at xt,yt) into raster array pixtarget at (0,0) */
/*                                                                          */
/*	SHOULD:	Perform ROP onto the raster array pixtarget at (xo,yo).	    */
/*		The source is pixsource (at sx,sy).  The extent is (dx,dy). */
/*		The pattern is replicated from the pixpat tile (size dx,dy).*/
/****************************************************************************/
Cerror          bitblt_patterned_source_array(pixpat, px, py, pixsource, sx, sy,
		                      pixtarget, rx, ry, ox, oy, dx, dy, name)
Cpixrect       *pixpat;		/* pattern source array */
Cint            px, py;		/* pattern extent */
Cpixrect       *pixsource;	/* source array */
Cint            sx, sy;		/* source origin */
Cpixrect       *pixtarget;	/* destination pattern array */
Cint            rx, ry;		/* pattern reference point */
Cint            ox, oy;		/* destination origin */
Cint            dx, dy;		/* destination extent */
Cint            name;
/* dx & dy and rx & ry are device coordinates.  Other coordinates are in VDC. */
{
    int             err;
    int             height, width, x, x1, y, y1;
    Pixrect        *mprect_sou, *mprect_pat, *mprect_target;

    err = _cgi_err_check_4();
    if (!pixpat)
	err = EPXNOTCR;
    if (!err)
    {
	_cgi_devscale(ox, oy, x1, y1);	/* target */
	_cgi_devscale(sx, sy, x, y);	/* source */
	width = dx;		/* x and y extent */
	height = dy;
	err = _cgi_err_check_69(x, y);
	if (!err)
	    err = _cgi_err_check_69(x1, y1);
	if (!err)
	{
	    err = _cgi_context(name);
	    if (!err)
	    {
		if ((pixsource->pr_depth == _cgi_vws->sunview.depth)
		    && (pixsource->pr_width >= width)
		    && (pixsource->pr_height >= height)
		    )
		    mprect_sou = pixsource;
		else
		    mprect_sou = mem_create(dx, dy, _cgi_vws->sunview.depth);
		/*
		 * Won't do my work in user's pixrects; they may be too small 
		 */

		if ((pixtarget->pr_depth == _cgi_vws->sunview.depth)
		    && (pixtarget->pr_width >= width)
		    && (pixtarget->pr_height >= height)
		    )
		    mprect_target = pixtarget;
		else
		    mprect_target = mem_create(dx, dy, _cgi_vws->sunview.depth);
		/*
		 * Won't do my work in user's pixrects; they may be too small 
		 */

		/* replicate pattern into mprect_pat: stencil must have depth=1 */
		mprect_pat = mem_create(dx, dy, 1);
		/*
		 * Where repeated pattern tile is non-zero, full-size stencil
		 * will be binary 1. 
		 */
		if (pixpat->pr_depth == 1)
		{
		    (void) pr_replrop(mprect_pat, 0, 0, dx, dy,
				      PIX_SRC, pixpat, rx % px, ry % py);
		}
		else
		{
		    Pixrect        *mprect1;	/* 1-bit-deep pattern tile */

		    mprect1 = mem_create(px, py, 1);
		    (void) _cgi_make_1_deep(mprect1, pixpat, px, py);
		    (void) pr_replrop(mprect_pat, 0, 0, dx, dy,
				      PIX_SRC, mprect1, rx % px, ry % py);
		    (void) pr_destroy(mprect1);	/* no longer need pixrect */
		}

		/* read SRC from screen into mprect_sou */
		pw_read(mprect_sou, 0, 0, width, height, PIX_SRC,
			_cgi_vws->sunview.pw, x, y);

		/* read target area of screen into pixtarget */
		pw_read(mprect_target, 0, 0, width, height, PIX_SRC,
			_cgi_vws->sunview.pw, x1, y1);

		/* ROP mprect_sou onto pixtarget using mprect_pat as mask */
		/* WDS: SunWindows Ref (p 2-10) says must be depth 1 */
		(void) pr_stencil(mprect_target, 0, 0, dx, dy,
				  _cgi_pix_drawing_mode,
				  mprect_pat, 0, 0, mprect_sou, 0, 0);

		/* where mprect_pat was zero mprect_target is unchanged */
		/* COPY onto screen the result of src and pattern */
		pw_write(_cgi_vws->sunview.pw, x1, y1, dx, dy,
			 PIX_SRC, mprect_target, 0, 0);
		/* result on screen is also in mprect_target */

		/*
		 * copy mprect_sou to user's pixsource, if they are different
		 * pixrects 
		 */
		if (pixsource && mprect_sou != pixsource)
		{
		    (void) pr_rop(pixsource, 0, 0, dx, dy, PIX_SRC,
				  mprect_sou, 0, 0);
		    (void) pr_destroy(mprect_sou);
		}

		/*
		 * copy mprect_target to user's pixtarget, if they are
		 * different pixrects 
		 */
		if (pixtarget && mprect_target != pixtarget)
		{
		    (void) pr_rop(pixtarget, 0, 0, dx, dy, PIX_SRC,
				  mprect_target, 0, 0);
		    (void) pr_destroy(mprect_target);
		}
	    }
	}
    }
    return (_cgi_errhand(err));
}

/****************************************************************************/
/*                                                                          */
/*     FUNCTION: set_global_drawing_mode				    */
/*                                                                          */
/*                                                                          */
/*		Determines how most primitives are displayed		    */
/****************************************************************************/

Cerror          set_global_drawing_mode(combination)
Ccombtype       combination;	/* combination rules */
{
    int             err;

    err = _cgi_check_state_5();
    if (!err)
    {
	_cgi_drawing_mode = combination;
	switch (_cgi_drawing_mode)
	{
	case REPLACE:
	    _cgi_pix_mode = PIX_SRC;
	    break;
	case AND:
	    _cgi_pix_mode = PIX_DST & PIX_SRC;
	    break;
	case OR:
	    _cgi_pix_mode = PIX_DST | PIX_SRC;
	    break;
	case NOT:
	    _cgi_pix_mode = PIX_NOT(PIX_SRC);
	    break;
	case XOR:
	    _cgi_pix_mode = PIX_SRC ^ PIX_DST;
	    break;
	}
    }
    return (_cgi_errhand(err));
}

/****************************************************************************/
/*                                                                          */
/*     FUNCTION: set_drawing_mode (index)				    */
/*                                                                          */
/*		Determines how bitblt primitives are displayed		    */
/****************************************************************************/

Cerror          set_drawing_mode(visibility, source, destination, combination)
Cbmode          visibility;	/* transparent or opaque */
Cbitmaptype     source;		/* NOT source bits */
Cbitmaptype     destination;	/* NOT destination bits */
Ccombtype       combination;	/* combination rules */
{
    int             pix_src, pix_dst;
    int             err;

    err = _cgi_check_state_5();
    if (!err)
    {
	_cgi_bit_drawing_mode = combination;
	_cgi_bit_vis_mode = visibility;
	_cgi_bit_source = source;
	_cgi_bit_dest = destination;
	pix_src = (source == BITNOT) ? PIX_NOT(PIX_SRC) : PIX_SRC;
	pix_dst = (destination == BITNOT) ? PIX_NOT(PIX_DST) : PIX_DST;
	switch (_cgi_pix_drawing_mode)
	{
	case REPLACE:
	    _cgi_pix_drawing_mode = pix_src;
	    break;
	case AND:
	    _cgi_pix_drawing_mode = pix_src & pix_dst;
	    break;
	case OR:
	    _cgi_pix_drawing_mode = pix_src | pix_dst;
	    break;
	case NOT:
	    _cgi_pix_drawing_mode = PIX_NOT(PIX_SRC);
	    /* wds: I choose to disregard (source == BITNOT) here. */
	    break;
	case XOR:
	    _cgi_pix_drawing_mode = pix_src ^ pix_dst;
	    break;
	}
    }
    return (_cgi_errhand(err));
}

/****************************************************************************/
/*                                                                          */
/*     FUNCTION: inquire_drawing_mode					    */
/*                                                                          */
/*                                                                          */
/****************************************************************************/

Cerror          inquire_drawing_mode(visibility, source, destination, combination)
Cbmode         *visibility;	/* transparent or opaque */
Cbitmaptype    *source;		/* NOT source bits */
Cbitmaptype    *destination;	/* NOT destination bits */
Ccombtype      *combination;	/* combination rules */
{
    int             err;

    err = _cgi_check_state_5();
    if (!err)
    {
	*combination = _cgi_bit_drawing_mode;
	*visibility = _cgi_bit_vis_mode;
	*source = _cgi_bit_source;
	*destination = _cgi_bit_dest;
    }
    return (_cgi_errhand(err));
}

/****************************************************************************/
/*                                                                          */
/*     FUNCTION:  inquire_device_bitmap (name)				    */
/*                                                                          */
/*                                                                          */
/****************************************************************************/

Cpixrect       *inquire_device_bitmap(name)
Cint            name;
{
    int             err;

    err = _cgi_context(name);
    if (!err)
	return (_cgi_vws->sunview.pw->pw_pixrect);
    else
	return (0);
}

/****************************************************************************/
/*                                                                          */
/*     FUNCTION: inquire_bitblt_alignments 				    */
/*                                                                          */
/*                                                                          */
/****************************************************************************/

Cerror          inquire_bitblt_alignments(base, width, px, py, maxpx, maxpy, name)
Cint           *base;		/* bitmap base alignment */
Cint           *width;		/* width alignment */
Cint           *px, *py;	/* pattern extent alignment */
Cint           *maxpx, *maxpy;	/* maximum pattern size */
Cint            name;
{
    int             err;

    err = _cgi_err_check_4();
    err = _cgi_context(name);
    if (!err)
    {
	if (!err)
	{
	    *base = 0;
	    *width = 0;
	    *px = 0;
	    *py = 0;
	    *maxpx = _cgi_vws->vport.r_width;
	    *maxpy = _cgi_vws->vport.r_height;
	}
    }
    return (_cgi_errhand(err));
}

/****************************************************************************/
/*                                                                          */
/*     FUNCTION: _cgi_make_1_deep					    */
/*                                                                          */
/*		Generates tile-size 1-bit-deep mask (stencil) pixrect	    */
/*		from any non-depth-1 pattern tile.			    */
/*		Treats any non-0 pattern as single-bit 1 pixel.		    */
/*		Memory pixrect is assumed to be all zeros from creation.    */
/*                                                                          */
/****************************************************************************/
static int      _cgi_make_1_deep(memrect, pixpat, px, py)
Cpixrect       *memrect;	/* stencil pixrect (px X py X 1-bit-deep) */
Cpixrect       *pixpat;		/* Pattern tile (px X py X n, n != 1) */
int             px, py;		/* Size of the pattern tile */
/* Note: memrect must already be mem_created, with all pixels zeroed. */
{
    register u_char *ptr8, *ptr1;	/* Pointers to pixels in tile, stencil */
    register short  i, j, bit_place;
    register u_char *stx8, *stx1;	/* Start of each ROW (in X) */
    register int    incx8, incx1;	/* Bytes in each ROW (in X) */

    if ((pixpat->pr_depth == 1) || (memrect->pr_depth != 1))
	return (1);		/* Arguments indicate improper use of this
				 * function */

    if ((pixpat->pr_width < px) || (pixpat->pr_height < py))
    {
	px = pixpat->pr_width;
	py = pixpat->pr_height;
    }
    stx8 = (u_char *) mprd8_addr(mpr_d(pixpat), 0, 0, pixpat->pr_depth);
    stx1 = (u_char *) mprd_addr(mpr_d(memrect), 0, 0);
    incx8 = mpr_mdlinebytes(pixpat);
    incx1 = mpr_mdlinebytes(memrect);

    for (i = 0; i < py; i++)	/* For each ROW in destination area */
    {
	ptr8 = stx8;
	ptr1 = stx1;
	bit_place = UCHAR_MSB;
	for (j = 0; j < px; j++)/* For each PIXEL in destination ROW */
	{			/* fill one row */
	    if (*ptr8++ != 0)
		*ptr1 |= bit_place;
#ifdef	i386
	    if ((bit_place <<= 1) == 0)
#else	!i386
	    if ((bit_place >>= 1) == 0)
#endif	i386
	    {
		bit_place = UCHAR_MSB;
		ptr1++;
	    }
	}
	stx8 += incx8;
	stx1 += incx1;
    }
    return (0);
}
