xref: /plan9/sys/src/cmd/gs/src/gdevpcfb.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1*593dc095SDavid du Colombier /* Copyright (C) 1989-2005 artofcode LLC.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevpcfb.c,v 1.7 2005/08/09 20:23:07 giles Exp $ */
187dd7cddfSDavid du Colombier /* IBM PC frame buffer (EGA/VGA) drivers */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "gconfigv.h"		/* for USE_ASM */
217dd7cddfSDavid du Colombier #include "gx.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gsparam.h"
247dd7cddfSDavid du Colombier #include "gxdevice.h"
257dd7cddfSDavid du Colombier #include "gdevpccm.h"
267dd7cddfSDavid du Colombier #include "gdevpcfb.h"
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier /* We may compile this in a non-segmented environment.... */
297dd7cddfSDavid du Colombier #ifndef _ss
307dd7cddfSDavid du Colombier #define _ss
317dd7cddfSDavid du Colombier #endif
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier /* Macro for casting gx_device argument */
347dd7cddfSDavid du Colombier #define fb_dev ((gx_device_ega *)dev)
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier /* Procedure record */
377dd7cddfSDavid du Colombier private dev_proc_map_rgb_color(ega0_map_rgb_color);
387dd7cddfSDavid du Colombier private dev_proc_map_rgb_color(ega1_map_rgb_color);
397dd7cddfSDavid du Colombier #define ega2_map_rgb_color pc_4bit_map_rgb_color
407dd7cddfSDavid du Colombier private dev_proc_map_color_rgb(ega01_map_color_rgb);
417dd7cddfSDavid du Colombier #define ega2_map_color_rgb pc_4bit_map_color_rgb
427dd7cddfSDavid du Colombier #if ega_bits_of_color == 0
437dd7cddfSDavid du Colombier #   define ega_map_rgb_color ega0_map_rgb_color
447dd7cddfSDavid du Colombier #   define ega_map_color_rgb ega01_map_color_rgb
457dd7cddfSDavid du Colombier #else
467dd7cddfSDavid du Colombier # if ega_bits_of_color == 1
477dd7cddfSDavid du Colombier #   define ega_map_rgb_color ega1_map_rgb_color
487dd7cddfSDavid du Colombier #   define ega_map_color_rgb ega01_map_color_rgb
497dd7cddfSDavid du Colombier # else
507dd7cddfSDavid du Colombier #   define ega_map_rgb_color ega2_map_rgb_color
517dd7cddfSDavid du Colombier #   define ega_map_color_rgb ega2_map_color_rgb
527dd7cddfSDavid du Colombier # endif
537dd7cddfSDavid du Colombier #endif
547dd7cddfSDavid du Colombier #define ega_std_procs(get_params, put_params)\
557dd7cddfSDavid du Colombier 	ega_open,\
567dd7cddfSDavid du Colombier 	NULL,			/* get_initial_matrix */\
577dd7cddfSDavid du Colombier 	NULL,			/* sync_output */\
587dd7cddfSDavid du Colombier 	NULL,			/* output_page */\
597dd7cddfSDavid du Colombier 	ega_close,\
607dd7cddfSDavid du Colombier 	ega_map_rgb_color,\
617dd7cddfSDavid du Colombier 	ega_map_color_rgb,\
627dd7cddfSDavid du Colombier 	ega_fill_rectangle,\
637dd7cddfSDavid du Colombier 	ega_tile_rectangle,\
647dd7cddfSDavid du Colombier 	ega_copy_mono,\
657dd7cddfSDavid du Colombier 	ega_copy_color,\
667dd7cddfSDavid du Colombier 	NULL,			/* draw_line */\
677dd7cddfSDavid du Colombier 	ega_get_bits,\
687dd7cddfSDavid du Colombier 	get_params,\
697dd7cddfSDavid du Colombier 	put_params,\
707dd7cddfSDavid du Colombier 	NULL,			/* map_cmyk_color */\
717dd7cddfSDavid du Colombier 	NULL,			/* get_xfont_procs */\
727dd7cddfSDavid du Colombier 	NULL,			/* get_xfont_device */\
737dd7cddfSDavid du Colombier 	NULL,			/* map_rgb_alpha_color */\
747dd7cddfSDavid du Colombier 	gx_page_device_get_page_device
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier private const gx_device_procs ega_procs =
777dd7cddfSDavid du Colombier {
787dd7cddfSDavid du Colombier     ega_std_procs(NULL, NULL)
797dd7cddfSDavid du Colombier };
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier private dev_proc_get_params(svga16_get_params);
827dd7cddfSDavid du Colombier private dev_proc_put_params(svga16_put_params);
837dd7cddfSDavid du Colombier private const gx_device_procs svga16_procs =
847dd7cddfSDavid du Colombier {
857dd7cddfSDavid du Colombier     ega_std_procs(svga16_get_params, svga16_put_params)
867dd7cddfSDavid du Colombier };
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier /* All the known instances */
897dd7cddfSDavid du Colombier 		/* EGA */
907dd7cddfSDavid du Colombier gx_device_ega far_data gs_ega_device =
917dd7cddfSDavid du Colombier ega_device("ega", ega_procs, 80, 350, 48.0 / 35.0, 0x10);
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier 		/* VGA */
947dd7cddfSDavid du Colombier gx_device_ega far_data gs_vga_device =
957dd7cddfSDavid du Colombier ega_device("vga", ega_procs, 80, 480, 1.0, 0x12);
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier 		/* Generic SuperVGA, 800x600, 16-color mode */
987dd7cddfSDavid du Colombier gx_device_ega far_data gs_svga16_device =
997dd7cddfSDavid du Colombier ega_device("svga16", svga16_procs, 100, 600, 1.0, 0x29 /*Tseng */ );
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier /* Save the BIOS state */
1027dd7cddfSDavid du Colombier private pcfb_bios_state pcfb_save_state =
1037dd7cddfSDavid du Colombier {-1};
1047dd7cddfSDavid du Colombier 
1057dd7cddfSDavid du Colombier /* Initialize the EGA for graphics mode */
1067dd7cddfSDavid du Colombier int
ega_open(gx_device * dev)1077dd7cddfSDavid du Colombier ega_open(gx_device * dev)
1087dd7cddfSDavid du Colombier {				/* Adjust the device resolution. */
1097dd7cddfSDavid du Colombier     /* This is a hack, pending refactoring of the put_params machinery. */
1107dd7cddfSDavid du Colombier     switch (fb_dev->video_mode) {
1117dd7cddfSDavid du Colombier 	case 0x10:		/* EGA */
1127dd7cddfSDavid du Colombier 	    gx_device_adjust_resolution(dev, 640, 350, 1);
1137dd7cddfSDavid du Colombier 	    break;
1147dd7cddfSDavid du Colombier 	case 0x12:		/* VGA */
1157dd7cddfSDavid du Colombier 	    gx_device_adjust_resolution(dev, 640, 480, 1);
1167dd7cddfSDavid du Colombier 	    break;
1177dd7cddfSDavid du Colombier 	default:		/* 800x600 SuperVGA */
1187dd7cddfSDavid du Colombier 	    gx_device_adjust_resolution(dev, 800, 600, 1);
1197dd7cddfSDavid du Colombier 	    break;
1207dd7cddfSDavid du Colombier     }
1217dd7cddfSDavid du Colombier     if (pcfb_save_state.display_mode < 0)
1227dd7cddfSDavid du Colombier 	pcfb_get_state(&pcfb_save_state);
1237dd7cddfSDavid du Colombier     /* Do implementation-specific initialization */
1247dd7cddfSDavid du Colombier     pcfb_set_signals(dev);
1257dd7cddfSDavid du Colombier     pcfb_set_mode(fb_dev->video_mode);
1267dd7cddfSDavid du Colombier     set_s_map(-1);		/* enable all maps */
1277dd7cddfSDavid du Colombier     return 0;
1287dd7cddfSDavid du Colombier }
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier /* Reinitialize the EGA for text mode */
1317dd7cddfSDavid du Colombier int
ega_close(gx_device * dev)1327dd7cddfSDavid du Colombier ega_close(gx_device * dev)
1337dd7cddfSDavid du Colombier {
1347dd7cddfSDavid du Colombier     if (pcfb_save_state.display_mode >= 0)
1357dd7cddfSDavid du Colombier 	pcfb_set_state(&pcfb_save_state);
1367dd7cddfSDavid du Colombier     return 0;
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier /* Get/put the display mode parameter. */
1407dd7cddfSDavid du Colombier private int
svga16_get_params(gx_device * dev,gs_param_list * plist)1417dd7cddfSDavid du Colombier svga16_get_params(gx_device * dev, gs_param_list * plist)
1427dd7cddfSDavid du Colombier {
1437dd7cddfSDavid du Colombier     int code = gx_default_get_params(dev, plist);
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier     if (code < 0)
1467dd7cddfSDavid du Colombier 	return code;
1477dd7cddfSDavid du Colombier     return param_write_int(plist, "DisplayMode", &fb_dev->video_mode);
1487dd7cddfSDavid du Colombier }
1497dd7cddfSDavid du Colombier private int
svga16_put_params(gx_device * dev,gs_param_list * plist)1507dd7cddfSDavid du Colombier svga16_put_params(gx_device * dev, gs_param_list * plist)
1517dd7cddfSDavid du Colombier {
1527dd7cddfSDavid du Colombier     int ecode = 0;
1537dd7cddfSDavid du Colombier     int code;
1547dd7cddfSDavid du Colombier     int imode = fb_dev->video_mode;
1557dd7cddfSDavid du Colombier     const char *param_name;
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier     switch (code = param_read_int(plist, (param_name = "DisplayMode"), &imode)) {
1587dd7cddfSDavid du Colombier 	default:
1597dd7cddfSDavid du Colombier 	    ecode = code;
1607dd7cddfSDavid du Colombier 	    param_signal_error(plist, param_name, ecode);
1617dd7cddfSDavid du Colombier 	case 0:
1627dd7cddfSDavid du Colombier 	case 1:
1637dd7cddfSDavid du Colombier 	    break;
1647dd7cddfSDavid du Colombier     }
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier     if (ecode < 0)
1677dd7cddfSDavid du Colombier 	return ecode;
1687dd7cddfSDavid du Colombier     code = gx_default_put_params(dev, plist);
1697dd7cddfSDavid du Colombier     if (code < 0)
1707dd7cddfSDavid du Colombier 	return code;
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier     if (imode != fb_dev->video_mode) {
1737dd7cddfSDavid du Colombier 	if (dev->is_open)
1747dd7cddfSDavid du Colombier 	    gs_closedevice(dev);
1757dd7cddfSDavid du Colombier 	fb_dev->video_mode = imode;
1767dd7cddfSDavid du Colombier     }
1777dd7cddfSDavid du Colombier     return 0;
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier /* Map a r-g-b color to an EGA color code. */
1817dd7cddfSDavid du Colombier private gx_color_index
ega0_map_rgb_color(gx_device * dev,const gx_color_value cv[])182*593dc095SDavid du Colombier ega0_map_rgb_color(gx_device * dev, const gx_color_value cv[])
1837dd7cddfSDavid du Colombier {
184*593dc095SDavid du Colombier     return pc_4bit_map_rgb_color(dev, cv);
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier private gx_color_index
ega1_map_rgb_color(gx_device * dev,const gx_color_value cv[])187*593dc095SDavid du Colombier ega1_map_rgb_color(gx_device * dev, const gx_color_value cv[])
1887dd7cddfSDavid du Colombier {
189*593dc095SDavid du Colombier     const gx_color_value cvtop = (1 << (gx_color_value_bits - 1));
190*593dc095SDavid du Colombier     gx_color_value cvt[3];
191*593dc095SDavid du Colombier     cvt[0] = cv[0] & cvtop;
192*593dc095SDavid du Colombier     cvt[1] = cv[1] & cvtop;
193*593dc095SDavid du Colombier     cvt[2] = cv[2] & cvtop;
194*593dc095SDavid du Colombier     return pc_4bit_map_rgb_color(dev, cvt);
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier /* Map a color code to r-g-b. */
1987dd7cddfSDavid du Colombier #define icolor (int)color
1997dd7cddfSDavid du Colombier private int
ega01_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])2007dd7cddfSDavid du Colombier ega01_map_color_rgb(gx_device * dev, gx_color_index color,
2017dd7cddfSDavid du Colombier 		    gx_color_value prgb[3])
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier #define one (gx_max_color_value / 2 + 1)
2047dd7cddfSDavid du Colombier     prgb[0] = (icolor & 4 ? one : 0);
2057dd7cddfSDavid du Colombier     prgb[1] = (icolor & 2 ? one : 0);
2067dd7cddfSDavid du Colombier     prgb[2] = (icolor & 1 ? one : 0);
2077dd7cddfSDavid du Colombier     return 0;
2087dd7cddfSDavid du Colombier #undef one
2097dd7cddfSDavid du Colombier }
2107dd7cddfSDavid du Colombier #undef icolor
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier /* Structure for operation parameters. */
2157dd7cddfSDavid du Colombier /* Note that this structure is known to assembly code. */
2167dd7cddfSDavid du Colombier /* Not all parameters are used for every operation. */
2177dd7cddfSDavid du Colombier typedef struct rop_params_s {
2187dd7cddfSDavid du Colombier     fb_ptr dest;		/* pointer to frame buffer */
2197dd7cddfSDavid du Colombier     int draster;		/* raster of frame buffer */
2207dd7cddfSDavid du Colombier     const byte *src;		/* pointer to source data */
2217dd7cddfSDavid du Colombier     int sraster;		/* source raster */
2227dd7cddfSDavid du Colombier     int width;			/* width in bytes */
2237dd7cddfSDavid du Colombier     int height;			/* height in scan lines */
2247dd7cddfSDavid du Colombier     int shift;			/* amount to right shift source */
2257dd7cddfSDavid du Colombier     int invert;			/* 0 or -1 to invert source */
2267dd7cddfSDavid du Colombier     int data;			/* data for fill */
2277dd7cddfSDavid du Colombier } rop_params;
2287dd7cddfSDavid du Colombier typedef rop_params _ss *rop_ptr;
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier /* Assembly language routines */
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier #if USE_ASM
233*593dc095SDavid du Colombier void memsetcol(rop_ptr);	/* dest, draster, height, data */
2347dd7cddfSDavid du Colombier #else
2357dd7cddfSDavid du Colombier #define memsetcol cmemsetcol
2367dd7cddfSDavid du Colombier private void
cmemsetcol(rop_ptr rop)2377dd7cddfSDavid du Colombier cmemsetcol(rop_ptr rop)
2387dd7cddfSDavid du Colombier {
2397dd7cddfSDavid du Colombier     byte *addr = rop->dest;
2407dd7cddfSDavid du Colombier     int yc = rop->height;
2417dd7cddfSDavid du Colombier     byte data = rop->data;
2427dd7cddfSDavid du Colombier     int draster = rop->draster;
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier     while (yc--) {
2457dd7cddfSDavid du Colombier 	byte_discard(*addr);
2467dd7cddfSDavid du Colombier 	*addr = data;
2477dd7cddfSDavid du Colombier 	addr += draster;
2487dd7cddfSDavid du Colombier     }
2497dd7cddfSDavid du Colombier }
2507dd7cddfSDavid du Colombier #endif
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier #if USE_ASM
253*593dc095SDavid du Colombier void memsetrect(rop_ptr);	/* dest, draster, width, height, data */
2547dd7cddfSDavid du Colombier #else
2557dd7cddfSDavid du Colombier #define memsetrect cmemsetrect
2567dd7cddfSDavid du Colombier private void
cmemsetrect(rop_ptr rop)2577dd7cddfSDavid du Colombier cmemsetrect(rop_ptr rop)
2587dd7cddfSDavid du Colombier {
2597dd7cddfSDavid du Colombier     int yc = rop->height;
2607dd7cddfSDavid du Colombier     int width = rop->width;
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier     if (yc <= 0 || width <= 0)
2637dd7cddfSDavid du Colombier 	return;
2647dd7cddfSDavid du Colombier     {
2657dd7cddfSDavid du Colombier 	byte *addr = rop->dest;
2667dd7cddfSDavid du Colombier 	byte data = rop->data;
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 	if (width > 5) {	/* use memset */
2697dd7cddfSDavid du Colombier 	    int skip = rop->draster;
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	    do {
2727dd7cddfSDavid du Colombier 		memset(addr, data, width);
2737dd7cddfSDavid du Colombier 		addr += skip;
2747dd7cddfSDavid du Colombier 	    }
2757dd7cddfSDavid du Colombier 	    while (--yc);
2767dd7cddfSDavid du Colombier 	} else {		/* avoid the fixed overhead */
2777dd7cddfSDavid du Colombier 	    int skip = rop->draster - width;
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 	    do {
2807dd7cddfSDavid du Colombier 		int cnt = width;
2817dd7cddfSDavid du Colombier 
2827dd7cddfSDavid du Colombier 		do {
2837dd7cddfSDavid du Colombier 		    *addr++ = data;
2847dd7cddfSDavid du Colombier 		} while (--cnt);
2857dd7cddfSDavid du Colombier 		addr += skip;
2867dd7cddfSDavid du Colombier 	    }
2877dd7cddfSDavid du Colombier 	    while (--yc);
2887dd7cddfSDavid du Colombier 	}
2897dd7cddfSDavid du Colombier     }
2907dd7cddfSDavid du Colombier }
2917dd7cddfSDavid du Colombier #endif
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier #if USE_ASM
294*593dc095SDavid du Colombier void memrwcol(rop_ptr);	/* dest, draster, src, sraster, height, shift, invert */
2957dd7cddfSDavid du Colombier #  define memrwcol0(rop) memrwcol(rop)	/* same except shift = 0 */
2967dd7cddfSDavid du Colombier #else
2977dd7cddfSDavid du Colombier #  define memrwcol cmemrwcol
2987dd7cddfSDavid du Colombier #  define memrwcol0 cmemrwcol0
2997dd7cddfSDavid du Colombier private void
cmemrwcol(rop_ptr rop)3007dd7cddfSDavid du Colombier cmemrwcol(rop_ptr rop)
3017dd7cddfSDavid du Colombier {
3027dd7cddfSDavid du Colombier     byte *dp = rop->dest;
3037dd7cddfSDavid du Colombier     const byte *sp = rop->src;
3047dd7cddfSDavid du Colombier     int yc = rop->height;
3057dd7cddfSDavid du Colombier     int shift = rop->shift;
3067dd7cddfSDavid du Colombier     byte invert = rop->invert;
3077dd7cddfSDavid du Colombier     int sraster = rop->sraster, draster = rop->draster;
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier     while (yc--) {
3107dd7cddfSDavid du Colombier 	byte_discard(*dp);
3117dd7cddfSDavid du Colombier 	*dp = ((*sp >> shift) + (*sp << (8 - shift))) ^ invert;
3127dd7cddfSDavid du Colombier 	dp += draster, sp += sraster;
3137dd7cddfSDavid du Colombier     }
3147dd7cddfSDavid du Colombier }
3157dd7cddfSDavid du Colombier private void
cmemrwcol0(rop_ptr rop)3167dd7cddfSDavid du Colombier cmemrwcol0(rop_ptr rop)
3177dd7cddfSDavid du Colombier {
3187dd7cddfSDavid du Colombier     byte *dp = rop->dest;
3197dd7cddfSDavid du Colombier     const byte *sp = rop->src;
3207dd7cddfSDavid du Colombier     int yc = rop->height;
3217dd7cddfSDavid du Colombier     byte invert = rop->invert;
3227dd7cddfSDavid du Colombier     int sraster = rop->sraster, draster = rop->draster;
3237dd7cddfSDavid du Colombier 
3247dd7cddfSDavid du Colombier     if (yc > 0)
3257dd7cddfSDavid du Colombier 	do {
3267dd7cddfSDavid du Colombier 	    byte_discard(*dp);
3277dd7cddfSDavid du Colombier 	    *dp = *sp ^ invert;
3287dd7cddfSDavid du Colombier 	    dp += draster, sp += sraster;
3297dd7cddfSDavid du Colombier 	}
3307dd7cddfSDavid du Colombier 	while (--yc);
3317dd7cddfSDavid du Colombier }
3327dd7cddfSDavid du Colombier #endif
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier #if USE_ASM
335*593dc095SDavid du Colombier void memrwcol2(rop_ptr);	/* dest, draster, src, sraster, height, shift, invert */
3367dd7cddfSDavid du Colombier #else
3377dd7cddfSDavid du Colombier #define memrwcol2 cmemrwcol2
3387dd7cddfSDavid du Colombier private void
cmemrwcol2(rop_ptr rop)3397dd7cddfSDavid du Colombier cmemrwcol2(rop_ptr rop)
3407dd7cddfSDavid du Colombier {
3417dd7cddfSDavid du Colombier     byte *dp = rop->dest;
3427dd7cddfSDavid du Colombier     const byte *sp = rop->src;
3437dd7cddfSDavid du Colombier     int yc = rop->height;
3447dd7cddfSDavid du Colombier     int shift = rop->shift;
3457dd7cddfSDavid du Colombier     byte invert = rop->invert;
3467dd7cddfSDavid du Colombier     int sraster = rop->sraster, draster = rop->draster;
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier     while (yc--) {
3497dd7cddfSDavid du Colombier 	byte_discard(*dp);
3507dd7cddfSDavid du Colombier 	*dp = ((sp[1] >> shift) + (*sp << (8 - shift))) ^ invert;
3517dd7cddfSDavid du Colombier 	dp += draster, sp += sraster;
3527dd7cddfSDavid du Colombier     }
3537dd7cddfSDavid du Colombier }
3547dd7cddfSDavid du Colombier #endif
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier /* Forward definitions */
357*593dc095SDavid du Colombier int ega_write_dot(gx_device *, int, int, gx_color_index);
358*593dc095SDavid du Colombier private void fill_rectangle(rop_ptr, int, int, int);
359*593dc095SDavid du Colombier private void fill_row_only(byte *, int, int, int);
3607dd7cddfSDavid du Colombier 
3617dd7cddfSDavid du Colombier /* Clean up after writing */
3627dd7cddfSDavid du Colombier #define dot_end()\
3637dd7cddfSDavid du Colombier   set_g_mask(0xff)		/* all bits on */
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier /* Write a dot using the EGA color codes. */
3667dd7cddfSDavid du Colombier /* This doesn't have to be efficient. */
3677dd7cddfSDavid du Colombier int
ega_write_dot(gx_device * dev,int x,int y,gx_color_index color)3687dd7cddfSDavid du Colombier ega_write_dot(gx_device * dev, int x, int y, gx_color_index color)
3697dd7cddfSDavid du Colombier {
3707dd7cddfSDavid du Colombier     byte data[4];
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier     data[0] = (byte) color;
3737dd7cddfSDavid du Colombier     return ega_copy_color(dev, data, 1, 4, gx_no_bitmap_id, x, y, 1, 1);
3747dd7cddfSDavid du Colombier }
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier /* Macro for testing bit-inclusion */
3777dd7cddfSDavid du Colombier #define bit_included_in(x,y) !((x)&~(y))
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier /* Copy a monochrome bitmap.  The colors are given explicitly. */
3807dd7cddfSDavid du Colombier /* Color = gx_no_color_index means transparent (no effect on the image). */
3817dd7cddfSDavid du Colombier int
ega_copy_mono(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index izero,gx_color_index ione)3827dd7cddfSDavid du Colombier ega_copy_mono(gx_device * dev,
3837dd7cddfSDavid du Colombier 	      const byte * base, int sourcex, int raster, gx_bitmap_id id,
3847dd7cddfSDavid du Colombier       int x, int y, int w, int h, gx_color_index izero, gx_color_index ione)
3857dd7cddfSDavid du Colombier {
3867dd7cddfSDavid du Colombier     rop_params params;
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier #define czero (int)izero
3897dd7cddfSDavid du Colombier #define cone (int)ione
3907dd7cddfSDavid du Colombier     int dleft, count;
3917dd7cddfSDavid du Colombier     byte mask, rmask;
3927dd7cddfSDavid du Colombier     fb_ptr save_dest;
3937dd7cddfSDavid du Colombier     int other_color = -1;
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
3967dd7cddfSDavid du Colombier     params.dest = mk_fb_ptr(x, y);
3977dd7cddfSDavid du Colombier     params.draster = fb_dev->raster;
3987dd7cddfSDavid du Colombier     params.src = base + (sourcex >> 3);
3997dd7cddfSDavid du Colombier     params.sraster = raster;
4007dd7cddfSDavid du Colombier     params.height = h;
4017dd7cddfSDavid du Colombier     params.shift = (x - sourcex) & 7;
4027dd7cddfSDavid du Colombier     /* Analyze the 16 possible cases: each of izero and ione may be */
4037dd7cddfSDavid du Colombier     /* 0, 0xf, transparent, or some other color. */
4047dd7cddfSDavid du Colombier     switch (czero) {
4057dd7cddfSDavid du Colombier 	case no_color:
4067dd7cddfSDavid du Colombier 	    switch (cone) {
4077dd7cddfSDavid du Colombier 		default:	/* (T, other) */
4087dd7cddfSDavid du Colombier 		    /* Must do 2 passes */
4097dd7cddfSDavid du Colombier 		    other_color = cone;
4107dd7cddfSDavid du Colombier 		    save_dest = params.dest;
4117dd7cddfSDavid du Colombier 		    /* falls through */
4127dd7cddfSDavid du Colombier 		case 0:	/* (T, 0) */
4137dd7cddfSDavid du Colombier 		    set_g_function(gf_AND);
4147dd7cddfSDavid du Colombier 		    params.invert = -1;
4157dd7cddfSDavid du Colombier 		    break;
4167dd7cddfSDavid du Colombier 		case 0xf:	/* (T, 0xf) */
4177dd7cddfSDavid du Colombier 		    set_g_function(gf_OR);
4187dd7cddfSDavid du Colombier 		    params.invert = 0;
4197dd7cddfSDavid du Colombier 		    break;
4207dd7cddfSDavid du Colombier 		case no_color:	/* (T, T) */
4217dd7cddfSDavid du Colombier 		    return 0;	/* nothing to do */
4227dd7cddfSDavid du Colombier 	    }
4237dd7cddfSDavid du Colombier 	    break;
4247dd7cddfSDavid du Colombier 	case 0:
4257dd7cddfSDavid du Colombier 	    params.invert = 0;
4267dd7cddfSDavid du Colombier 	    switch (cone) {
4277dd7cddfSDavid du Colombier 		default:	/* (0, other) */
4287dd7cddfSDavid du Colombier 		    set_g_const(0);
4297dd7cddfSDavid du Colombier 		    set_g_const_map(cone ^ 0xf);
4307dd7cddfSDavid du Colombier 		    /* falls through */
4317dd7cddfSDavid du Colombier 		case 0xf:	/* (0, 0xf) */
4327dd7cddfSDavid du Colombier 		    break;
4337dd7cddfSDavid du Colombier 		case no_color:	/* (0, T) */
4347dd7cddfSDavid du Colombier 		    set_g_function(gf_AND);
4357dd7cddfSDavid du Colombier 		    break;
4367dd7cddfSDavid du Colombier 	    }
4377dd7cddfSDavid du Colombier 	    break;
4387dd7cddfSDavid du Colombier 	case 0xf:
4397dd7cddfSDavid du Colombier 	    params.invert = -1;
4407dd7cddfSDavid du Colombier 	    switch (cone) {
4417dd7cddfSDavid du Colombier 		case 0:	/* (0xf, 0) */
4427dd7cddfSDavid du Colombier 		    break;
4437dd7cddfSDavid du Colombier 		default:	/* (0xf, other) */
4447dd7cddfSDavid du Colombier 		    set_g_const(0xf);
4457dd7cddfSDavid du Colombier 		    set_g_const_map(cone);
4467dd7cddfSDavid du Colombier 		    break;
4477dd7cddfSDavid du Colombier 		case no_color:	/* (0xf, T) */
4487dd7cddfSDavid du Colombier 		    set_g_function(gf_OR);
4497dd7cddfSDavid du Colombier 		    /* falls through */
4507dd7cddfSDavid du Colombier 	    }
4517dd7cddfSDavid du Colombier 	    break;
4527dd7cddfSDavid du Colombier 	default:
4537dd7cddfSDavid du Colombier 	    switch (cone) {
4547dd7cddfSDavid du Colombier 		default:	/* (other, not T) */
4557dd7cddfSDavid du Colombier 		    if (bit_included_in(czero, cone)) {
4567dd7cddfSDavid du Colombier 			set_g_const(czero);
4577dd7cddfSDavid du Colombier 			set_g_const_map(czero ^ cone ^ 0xf);
4587dd7cddfSDavid du Colombier 			params.invert = 0;
4597dd7cddfSDavid du Colombier 			break;
4607dd7cddfSDavid du Colombier 		    } else if (bit_included_in(cone, czero)) {
4617dd7cddfSDavid du Colombier 			set_g_const(cone);
4627dd7cddfSDavid du Colombier 			set_g_const_map(cone ^ czero ^ 0xf);
4637dd7cddfSDavid du Colombier 			params.invert = -1;
4647dd7cddfSDavid du Colombier 			break;
4657dd7cddfSDavid du Colombier 		    }
4667dd7cddfSDavid du Colombier 		    /* No way around it, fill with one color first. */
4677dd7cddfSDavid du Colombier 		    save_dest = params.dest;
4687dd7cddfSDavid du Colombier 		    fill_rectangle((rop_ptr) & params, x & 7, w, cone);
4697dd7cddfSDavid du Colombier 		    params.dest = save_dest;
4707dd7cddfSDavid du Colombier 		    set_g_function(gf_XOR);
4717dd7cddfSDavid du Colombier 		    set_s_map(czero ^ cone);
4727dd7cddfSDavid du Colombier 		    other_color = -2;	/* must reset s_map at end */
4737dd7cddfSDavid du Colombier 		    params.invert = -1;
4747dd7cddfSDavid du Colombier 		    break;
4757dd7cddfSDavid du Colombier 		case no_color:	/* (other, T) */
4767dd7cddfSDavid du Colombier 		    /* Must do 2 passes */
4777dd7cddfSDavid du Colombier 		    other_color = czero;
4787dd7cddfSDavid du Colombier 		    save_dest = params.dest;
4797dd7cddfSDavid du Colombier 		    set_g_function(gf_AND);
4807dd7cddfSDavid du Colombier 		    params.invert = 0;
4817dd7cddfSDavid du Colombier 		    break;
4827dd7cddfSDavid du Colombier 	    }
4837dd7cddfSDavid du Colombier 	    break;
4847dd7cddfSDavid du Colombier     }
4857dd7cddfSDavid du Colombier     /* Actually copy the bits. */
4867dd7cddfSDavid du Colombier     dleft = 8 - (x & 7);
4877dd7cddfSDavid du Colombier     mask = 0xff >> (8 - dleft);
4887dd7cddfSDavid du Colombier     count = w - dleft;
4897dd7cddfSDavid du Colombier     if (count < 0)
4907dd7cddfSDavid du Colombier 	mask -= mask >> w,
4917dd7cddfSDavid du Colombier 	    rmask = 0;
4927dd7cddfSDavid du Colombier     else
4937dd7cddfSDavid du Colombier 	rmask = 0xff00 >> (count & 7);
4947dd7cddfSDavid du Colombier     /* params: dest, src, sraster, height, shift, invert */
4957dd7cddfSDavid du Colombier     /* Smashes params.src, params.dest, count. */
4967dd7cddfSDavid du Colombier   copy:set_g_mask(mask);
4977dd7cddfSDavid du Colombier     if (params.shift == 0) {	/* optimize the aligned case *//* Do left column */
4987dd7cddfSDavid du Colombier 	memrwcol0((rop_ptr) & params);
4997dd7cddfSDavid du Colombier 	/* Do center */
5007dd7cddfSDavid du Colombier 	if ((count -= 8) >= 0) {
5017dd7cddfSDavid du Colombier 	    out_g_mask(0xff);
5027dd7cddfSDavid du Colombier 	    do {
5037dd7cddfSDavid du Colombier 		params.src++, params.dest++;
5047dd7cddfSDavid du Colombier 		memrwcol0((rop_ptr) & params);
5057dd7cddfSDavid du Colombier 	    }
5067dd7cddfSDavid du Colombier 	    while ((count -= 8) >= 0);
5077dd7cddfSDavid du Colombier 	}
5087dd7cddfSDavid du Colombier 	/* Do right column */
5097dd7cddfSDavid du Colombier 	if (rmask) {
5107dd7cddfSDavid du Colombier 	    params.src++, params.dest++;
5117dd7cddfSDavid du Colombier 	    out_g_mask(rmask);
5127dd7cddfSDavid du Colombier 	    memrwcol0((rop_ptr) & params);
5137dd7cddfSDavid du Colombier 	}
5147dd7cddfSDavid du Colombier     } else {			/* Do left column */
5157dd7cddfSDavid du Colombier 	int sleft = 8 - (sourcex & 7);
5167dd7cddfSDavid du Colombier 
5177dd7cddfSDavid du Colombier 	if (sleft >= dleft) {	/* Source fits in one byte */
5187dd7cddfSDavid du Colombier 	    memrwcol((rop_ptr) & params);
5197dd7cddfSDavid du Colombier 	} else if (w <= sleft) {	/* Source fits in one byte, thin case */
5207dd7cddfSDavid du Colombier 	    memrwcol((rop_ptr) & params);
5217dd7cddfSDavid du Colombier 	    goto fin;
5227dd7cddfSDavid du Colombier 	} else {
5237dd7cddfSDavid du Colombier 	    memrwcol2((rop_ptr) & params);
5247dd7cddfSDavid du Colombier 	    params.src++;
5257dd7cddfSDavid du Colombier 	}
5267dd7cddfSDavid du Colombier 	/* Do center */
5277dd7cddfSDavid du Colombier 	if ((count -= 8) >= 0) {
5287dd7cddfSDavid du Colombier 	    out_g_mask(0xff);
5297dd7cddfSDavid du Colombier 	    do {
5307dd7cddfSDavid du Colombier 		params.dest++;
5317dd7cddfSDavid du Colombier 		memrwcol2((rop_ptr) & params);
5327dd7cddfSDavid du Colombier 		params.src++;
5337dd7cddfSDavid du Colombier 	    }
5347dd7cddfSDavid du Colombier 	    while ((count -= 8) >= 0);
5357dd7cddfSDavid du Colombier 	}
5367dd7cddfSDavid du Colombier 	/* Do right column */
5377dd7cddfSDavid du Colombier 	if (rmask) {
5387dd7cddfSDavid du Colombier 	    out_g_mask(rmask);
5397dd7cddfSDavid du Colombier 	    params.dest++;
5407dd7cddfSDavid du Colombier 	    if (count + 8 <= params.shift)
5417dd7cddfSDavid du Colombier 		memrwcol((rop_ptr) & params);
5427dd7cddfSDavid du Colombier 	    else
5437dd7cddfSDavid du Colombier 		memrwcol2((rop_ptr) & params);
5447dd7cddfSDavid du Colombier 	}
5457dd7cddfSDavid du Colombier     }
5467dd7cddfSDavid du Colombier   fin:if (other_color != -1) {
5477dd7cddfSDavid du Colombier 	if (other_color >= 0) {	/* Do the second pass on (T, other) or (other, T). */
5487dd7cddfSDavid du Colombier 	    count = w - dleft;
5497dd7cddfSDavid du Colombier 	    params.src = base + (sourcex >> 3);
5507dd7cddfSDavid du Colombier 	    params.dest = save_dest;
5517dd7cddfSDavid du Colombier 	    params.invert ^= -1;
5527dd7cddfSDavid du Colombier 	    set_s_map(other_color);
5537dd7cddfSDavid du Colombier 	    set_g_function(gf_OR);
5547dd7cddfSDavid du Colombier 	    other_color = -2;
5557dd7cddfSDavid du Colombier 	    goto copy;
5567dd7cddfSDavid du Colombier 	} else {		/* Finished second pass, restore s_map */
5577dd7cddfSDavid du Colombier 	    set_s_map(-1);
5587dd7cddfSDavid du Colombier 	}
5597dd7cddfSDavid du Colombier     }
5607dd7cddfSDavid du Colombier     set_g_function(gf_WRITE);
5617dd7cddfSDavid du Colombier     set_g_const_map(0);
5627dd7cddfSDavid du Colombier     dot_end();
5637dd7cddfSDavid du Colombier     return 0;
5647dd7cddfSDavid du Colombier #undef czero
5657dd7cddfSDavid du Colombier #undef cone
5667dd7cddfSDavid du Colombier }
5677dd7cddfSDavid du Colombier 
5687dd7cddfSDavid du Colombier /* Copy a color pixelmap.  This is just like a bitmap, */
5697dd7cddfSDavid du Colombier /* except that each pixel takes 4 bits instead of 1. */
5707dd7cddfSDavid du Colombier int
ega_copy_color(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)5717dd7cddfSDavid du Colombier ega_copy_color(gx_device * dev,
5727dd7cddfSDavid du Colombier 	       const byte * base, int sourcex, int raster, gx_bitmap_id id,
5737dd7cddfSDavid du Colombier 	       int x, int y, int w, int h)
5747dd7cddfSDavid du Colombier {
5757dd7cddfSDavid du Colombier     const byte *line = base + (sourcex >> 1);
5767dd7cddfSDavid du Colombier     unsigned mask = 0x80 >> (x & 7);
5777dd7cddfSDavid du Colombier     int px = sourcex & 1;
5787dd7cddfSDavid du Colombier     fb_ptr fb_line;
5797dd7cddfSDavid du Colombier     int fb_raster = fb_dev->raster;
5807dd7cddfSDavid du Colombier 
5817dd7cddfSDavid du Colombier     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
5827dd7cddfSDavid du Colombier     fb_line = mk_fb_ptr(x, y);
5837dd7cddfSDavid du Colombier     set_g_mode(gm_FILL);
5847dd7cddfSDavid du Colombier     select_g_mask();
5857dd7cddfSDavid du Colombier     for (;; px++) {
5867dd7cddfSDavid du Colombier 	const byte *bptr = line;
5877dd7cddfSDavid du Colombier 	fb_ptr fbptr = fb_line;
5887dd7cddfSDavid du Colombier 	int py = h;
5897dd7cddfSDavid du Colombier 
5907dd7cddfSDavid du Colombier 	out_g_mask(mask);
5917dd7cddfSDavid du Colombier 	if (px & 1) {
5927dd7cddfSDavid du Colombier 	    do {
5937dd7cddfSDavid du Colombier 		byte_discard(*fbptr);	/* latch frame buffer data */
5947dd7cddfSDavid du Colombier 		*fbptr = *bptr;
5957dd7cddfSDavid du Colombier 		bptr += raster;
5967dd7cddfSDavid du Colombier 		fbptr += fb_raster;
5977dd7cddfSDavid du Colombier 	    }
5987dd7cddfSDavid du Colombier 	    while (--py);
5997dd7cddfSDavid du Colombier 	    line++;
6007dd7cddfSDavid du Colombier 	} else {
6017dd7cddfSDavid du Colombier 	    do {
6027dd7cddfSDavid du Colombier 		byte_discard(*fbptr);	/* latch frame buffer data */
6037dd7cddfSDavid du Colombier 		*fbptr = *bptr >> 4;
6047dd7cddfSDavid du Colombier 		bptr += raster;
6057dd7cddfSDavid du Colombier 		fbptr += fb_raster;
6067dd7cddfSDavid du Colombier 	    }
6077dd7cddfSDavid du Colombier 	    while (--py);
6087dd7cddfSDavid du Colombier 	}
6097dd7cddfSDavid du Colombier 	if (!--w)
6107dd7cddfSDavid du Colombier 	    break;
6117dd7cddfSDavid du Colombier 	if ((mask >>= 1) == 0)
6127dd7cddfSDavid du Colombier 	    mask = 0x80, fb_line++;
6137dd7cddfSDavid du Colombier     }
6147dd7cddfSDavid du Colombier     set_g_mode(gm_DATA);
6157dd7cddfSDavid du Colombier     dot_end();
6167dd7cddfSDavid du Colombier     return 0;
6177dd7cddfSDavid du Colombier }
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier /* Fill a rectangle. */
6207dd7cddfSDavid du Colombier int
ega_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)6217dd7cddfSDavid du Colombier ega_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
6227dd7cddfSDavid du Colombier 		   gx_color_index color)
6237dd7cddfSDavid du Colombier {
6247dd7cddfSDavid du Colombier     rop_params params;
6257dd7cddfSDavid du Colombier 
6267dd7cddfSDavid du Colombier     fit_fill(dev, x, y, w, h);
6277dd7cddfSDavid du Colombier     params.dest = mk_fb_ptr(x, y);
6287dd7cddfSDavid du Colombier     if (h == 1)
6297dd7cddfSDavid du Colombier 	fill_row_only(params.dest, x & 7, w, (int)color);
6307dd7cddfSDavid du Colombier     else {
6317dd7cddfSDavid du Colombier 	params.draster = fb_dev->raster;
6327dd7cddfSDavid du Colombier 	params.height = h;
6337dd7cddfSDavid du Colombier 	fill_rectangle((rop_ptr) & params, x & 7, w, (int)color);
6347dd7cddfSDavid du Colombier 	dot_end();
6357dd7cddfSDavid du Colombier     }
6367dd7cddfSDavid du Colombier     return 0;
6377dd7cddfSDavid du Colombier }
6387dd7cddfSDavid du Colombier 
6397dd7cddfSDavid du Colombier /* Tile a rectangle.  Note that the two colors must both be supplied, */
6407dd7cddfSDavid du Colombier /* i.e. neither one can be gx_no_color_index (transparent): */
6417dd7cddfSDavid du Colombier /* a transparent color means that the tile is colored, not a mask. */
6427dd7cddfSDavid du Colombier int
ega_tile_rectangle(gx_device * dev,const gx_tile_bitmap * tile,int x,int y,int w,int h,gx_color_index czero,gx_color_index cone,int px,int py)6437dd7cddfSDavid du Colombier ega_tile_rectangle(gx_device * dev, const gx_tile_bitmap * tile,
6447dd7cddfSDavid du Colombier       int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
6457dd7cddfSDavid du Colombier 		   int px, int py)
6467dd7cddfSDavid du Colombier #define zero (int)czero
6477dd7cddfSDavid du Colombier #define one (int)cone
6487dd7cddfSDavid du Colombier {
6497dd7cddfSDavid du Colombier     rop_params params;
6507dd7cddfSDavid du Colombier     int xmod, width_bytes;
6517dd7cddfSDavid du Colombier     int tile_height = tile->size.y;
6527dd7cddfSDavid du Colombier     int xbit;
6537dd7cddfSDavid du Colombier     int lcount;
6547dd7cddfSDavid du Colombier     int mask, rmask;
6557dd7cddfSDavid du Colombier     byte narrow;
6567dd7cddfSDavid du Colombier     byte again;
6577dd7cddfSDavid du Colombier     int const_bits, maps;
6587dd7cddfSDavid du Colombier     int ymod, yleft;
6597dd7cddfSDavid du Colombier 
6607dd7cddfSDavid du Colombier     fit_fill(dev, x, y, w, h);
6617dd7cddfSDavid du Colombier     /* We only handle the easiest cases directly. */
6627dd7cddfSDavid du Colombier     if ((tile->size.x & 7) || one == -1 || zero == -1 || px || py)
6637dd7cddfSDavid du Colombier 	return gx_default_tile_rectangle(dev, tile, x, y, w, h,
6647dd7cddfSDavid du Colombier 					 czero, cone, px, py);
6657dd7cddfSDavid du Colombier     /* Following is similar to aligned case of copy_mono */
6667dd7cddfSDavid du Colombier     params.dest = mk_fb_ptr(x, y);
6677dd7cddfSDavid du Colombier     params.draster = fb_dev->raster;
6687dd7cddfSDavid du Colombier     params.sraster = tile->raster;
6697dd7cddfSDavid du Colombier     params.shift = 0;
6707dd7cddfSDavid du Colombier     xbit = x & 7;
6717dd7cddfSDavid du Colombier     /* Set up the graphics registers */
6727dd7cddfSDavid du Colombier     const_bits = (zero ^ one) ^ 0xf;
6737dd7cddfSDavid du Colombier     if (const_bits) {
6747dd7cddfSDavid du Colombier 	set_g_const(zero);	/* either color will do */
6757dd7cddfSDavid du Colombier 	set_g_const_map(const_bits);
6767dd7cddfSDavid du Colombier     }
6777dd7cddfSDavid du Colombier     if ((maps = zero & ~one) != 0) {
6787dd7cddfSDavid du Colombier 	set_s_map(maps += const_bits);
6797dd7cddfSDavid du Colombier 	params.invert = -1;
6807dd7cddfSDavid du Colombier 	again = one & ~zero;
6817dd7cddfSDavid du Colombier     } else {
6827dd7cddfSDavid du Colombier 	maps = one & ~zero;
6837dd7cddfSDavid du Colombier 	set_s_map(maps += const_bits);
6847dd7cddfSDavid du Colombier 	params.invert = 0;
6857dd7cddfSDavid du Colombier 	again = 0;
6867dd7cddfSDavid du Colombier     }
6877dd7cddfSDavid du Colombier     xmod = (x % tile->size.x) >> 3;
6887dd7cddfSDavid du Colombier     width_bytes = tile->size.x >> 3;
6897dd7cddfSDavid du Colombier     mask = 0xff >> xbit;
6907dd7cddfSDavid du Colombier     if (w + xbit <= 8)
6917dd7cddfSDavid du Colombier 	mask -= mask >> w,
6927dd7cddfSDavid du Colombier 	    rmask = 0,
6937dd7cddfSDavid du Colombier 	    narrow = 1;
6947dd7cddfSDavid du Colombier     else {
6957dd7cddfSDavid du Colombier 	rmask = (0xff00 >> ((w + x) & 7)) & 0xff;
6967dd7cddfSDavid du Colombier 	if (xbit)
6977dd7cddfSDavid du Colombier 	    w += xbit - 8;
6987dd7cddfSDavid du Colombier 	else
6997dd7cddfSDavid du Colombier 	    mask = 0, --xmod, --params.dest;
7007dd7cddfSDavid du Colombier 	narrow = 0;
7017dd7cddfSDavid du Colombier     }
7027dd7cddfSDavid du Colombier     ymod = y % tile_height;
7037dd7cddfSDavid du Colombier   tile:yleft = tile_height - ymod;
7047dd7cddfSDavid du Colombier     params.src = tile->data + ymod * params.sraster + xmod;
7057dd7cddfSDavid du Colombier     lcount = h;
7067dd7cddfSDavid du Colombier     if (narrow) {		/* Optimize narrow case */
7077dd7cddfSDavid du Colombier 	set_g_mask(mask);
7087dd7cddfSDavid du Colombier 	if (lcount > yleft) {
7097dd7cddfSDavid du Colombier 	    params.height = yleft;
7107dd7cddfSDavid du Colombier 	    memrwcol0((rop_ptr) & params);
7117dd7cddfSDavid du Colombier 	    params.dest += yleft * params.draster;
7127dd7cddfSDavid du Colombier 	    params.src = tile->data + xmod;
7137dd7cddfSDavid du Colombier 	    params.height = tile_height;
7147dd7cddfSDavid du Colombier 	    lcount -= yleft;
7157dd7cddfSDavid du Colombier 	    while (lcount >= tile_height) {
7167dd7cddfSDavid du Colombier 		memrwcol0((rop_ptr) & params);
7177dd7cddfSDavid du Colombier 		params.dest += tile_height * params.draster;
7187dd7cddfSDavid du Colombier 		lcount -= tile_height;
7197dd7cddfSDavid du Colombier 	    }
7207dd7cddfSDavid du Colombier 	}
7217dd7cddfSDavid du Colombier 	if (lcount) {
7227dd7cddfSDavid du Colombier 	    params.height = lcount;
7237dd7cddfSDavid du Colombier 	    memrwcol0((rop_ptr) & params);
7247dd7cddfSDavid du Colombier 	}
7257dd7cddfSDavid du Colombier     } else {
7267dd7cddfSDavid du Colombier 	fb_ptr line = params.dest;
7277dd7cddfSDavid du Colombier 	int xpos = width_bytes - xmod;
7287dd7cddfSDavid du Colombier 
7297dd7cddfSDavid du Colombier 	while (1) {
7307dd7cddfSDavid du Colombier 	    int xleft = xpos;
7317dd7cddfSDavid du Colombier 	    int count = w;
7327dd7cddfSDavid du Colombier 
7337dd7cddfSDavid du Colombier 	    params.height = (lcount > yleft ? yleft : lcount);
7347dd7cddfSDavid du Colombier 	    /* Do first byte, if not a full byte. */
7357dd7cddfSDavid du Colombier 	    if (mask) {
7367dd7cddfSDavid du Colombier 		set_g_mask(mask);
7377dd7cddfSDavid du Colombier 		memrwcol0((rop_ptr) & params);
7387dd7cddfSDavid du Colombier 	    }
7397dd7cddfSDavid du Colombier 	    /* Do full bytes */
7407dd7cddfSDavid du Colombier 	    if ((count -= 8) >= 0) {
7417dd7cddfSDavid du Colombier 		set_g_mask(0xff);
7427dd7cddfSDavid du Colombier 		do {
7437dd7cddfSDavid du Colombier 		    if (!--xleft)
7447dd7cddfSDavid du Colombier 			xleft = width_bytes,
7457dd7cddfSDavid du Colombier 			    params.src -= width_bytes;
7467dd7cddfSDavid du Colombier 		    ++params.src, ++params.dest;
7477dd7cddfSDavid du Colombier 		    memrwcol0((rop_ptr) & params);
7487dd7cddfSDavid du Colombier 		}
7497dd7cddfSDavid du Colombier 		while ((count -= 8) >= 0);
7507dd7cddfSDavid du Colombier 	    }
7517dd7cddfSDavid du Colombier 	    /* Do last byte */
7527dd7cddfSDavid du Colombier 	    if (rmask) {
7537dd7cddfSDavid du Colombier 		if (!--xleft)
7547dd7cddfSDavid du Colombier 		    xleft = width_bytes,
7557dd7cddfSDavid du Colombier 			params.src -= width_bytes;
7567dd7cddfSDavid du Colombier 		set_g_mask(rmask);
7577dd7cddfSDavid du Colombier 		++params.src, ++params.dest;
7587dd7cddfSDavid du Colombier 		memrwcol0((rop_ptr) & params);
7597dd7cddfSDavid du Colombier 	    }
7607dd7cddfSDavid du Colombier 	    if ((lcount -= params.height) == 0)
7617dd7cddfSDavid du Colombier 		break;
7627dd7cddfSDavid du Colombier 	    params.dest = line += params.height * params.draster;
7637dd7cddfSDavid du Colombier 	    params.src = tile->data + xmod;
7647dd7cddfSDavid du Colombier 	    yleft = tile_height;
7657dd7cddfSDavid du Colombier 	}
7667dd7cddfSDavid du Colombier     }
7677dd7cddfSDavid du Colombier     /* Now do the second color if needed */
7687dd7cddfSDavid du Colombier     if (again) {
7697dd7cddfSDavid du Colombier 	maps = again + const_bits;
7707dd7cddfSDavid du Colombier 	set_s_map(maps);
7717dd7cddfSDavid du Colombier 	again = 0;
7727dd7cddfSDavid du Colombier 	params.dest = mk_fb_ptr(x, y);
7737dd7cddfSDavid du Colombier 	if (mask == 0)
7747dd7cddfSDavid du Colombier 	    params.dest--;
7757dd7cddfSDavid du Colombier 	params.invert = 0;
7767dd7cddfSDavid du Colombier 	goto tile;
7777dd7cddfSDavid du Colombier     }
7787dd7cddfSDavid du Colombier     if (maps != 0xf)
7797dd7cddfSDavid du Colombier 	set_s_map(-1);
7807dd7cddfSDavid du Colombier     if (const_bits)
7817dd7cddfSDavid du Colombier 	set_g_const_map(0);
7827dd7cddfSDavid du Colombier     dot_end();
7837dd7cddfSDavid du Colombier     return 0;
7847dd7cddfSDavid du Colombier }
7857dd7cddfSDavid du Colombier 
7867dd7cddfSDavid du Colombier /* Read scan lines back from the frame buffer. */
7877dd7cddfSDavid du Colombier int
ega_get_bits(gx_device * dev,int y,byte * data,byte ** actual_data)7887dd7cddfSDavid du Colombier ega_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
7897dd7cddfSDavid du Colombier {				/* The maximum width for an EGA/VGA device is 800 pixels.... */
7907dd7cddfSDavid du Colombier     int width_bytes = (dev->width + 7) >> 3;
7917dd7cddfSDavid du Colombier     int i;
7927dd7cddfSDavid du Colombier     bits32 *dest;
7937dd7cddfSDavid du Colombier     const byte *src;
7947dd7cddfSDavid du Colombier     const byte *end;
7957dd7cddfSDavid du Colombier     byte planes[100 * 4];
7967dd7cddfSDavid du Colombier 
7977dd7cddfSDavid du Colombier     /* Plane 0 is the least significant plane. */
7987dd7cddfSDavid du Colombier     /* We know we're on a little-endian machine.... */
7997dd7cddfSDavid du Colombier #define spread4(v)\
8007dd7cddfSDavid du Colombier  v+0x00000000, v+0x08000000, v+0x80000000, v+0x88000000,\
8017dd7cddfSDavid du Colombier  v+0x00080000, v+0x08080000, v+0x80080000, v+0x88080000,\
8027dd7cddfSDavid du Colombier  v+0x00800000, v+0x08800000, v+0x80800000, v+0x88800000,\
8037dd7cddfSDavid du Colombier  v+0x00880000, v+0x08880000, v+0x80880000, v+0x88880000
8047dd7cddfSDavid du Colombier     static const bits32 spread8[256] =
8057dd7cddfSDavid du Colombier     {spread4(0x0000), spread4(0x0800),
8067dd7cddfSDavid du Colombier      spread4(0x8000), spread4(0x8800),
8077dd7cddfSDavid du Colombier      spread4(0x0008), spread4(0x0808),
8087dd7cddfSDavid du Colombier      spread4(0x8008), spread4(0x8808),
8097dd7cddfSDavid du Colombier      spread4(0x0080), spread4(0x0880),
8107dd7cddfSDavid du Colombier      spread4(0x8080), spread4(0x8880),
8117dd7cddfSDavid du Colombier      spread4(0x0088), spread4(0x0888),
8127dd7cddfSDavid du Colombier      spread4(0x8088), spread4(0x8888)
8137dd7cddfSDavid du Colombier     };
8147dd7cddfSDavid du Colombier 
8157dd7cddfSDavid du Colombier     if (y < 0 || y >= dev->height || dev->width > 800)
8167dd7cddfSDavid du Colombier 	return_error(gs_error_rangecheck);
8177dd7cddfSDavid du Colombier     /* Read 4 planes into the holding buffer. */
8187dd7cddfSDavid du Colombier     for (i = 0; i < 4; ++i) {
8197dd7cddfSDavid du Colombier 	set_g_read_plane(i);
8207dd7cddfSDavid du Colombier 	memcpy(planes + 100 * i, mk_fb_ptr(0, y), width_bytes);
8217dd7cddfSDavid du Colombier     }
8227dd7cddfSDavid du Colombier     /* Now assemble the final data from the planes. */
8237dd7cddfSDavid du Colombier     for (dest = (bits32 *) data, src = planes, end = src + width_bytes;
8247dd7cddfSDavid du Colombier 	 src < end; ++dest, ++src
8257dd7cddfSDavid du Colombier 	)
8267dd7cddfSDavid du Colombier 	*dest = (((((spread8[src[0]] >> 1) | spread8[src[100]]) >> 1) |
8277dd7cddfSDavid du Colombier 		  spread8[src[200]]) >> 1) | spread8[src[300]];
8287dd7cddfSDavid du Colombier     if (actual_data != 0)
8297dd7cddfSDavid du Colombier 	*actual_data = data;
8307dd7cddfSDavid du Colombier     return 0;
8317dd7cddfSDavid du Colombier }
8327dd7cddfSDavid du Colombier 
8337dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
8347dd7cddfSDavid du Colombier 
8357dd7cddfSDavid du Colombier /* Mask table for rectangle fill. */
8367dd7cddfSDavid du Colombier static const byte rmask_tab[9] =
8377dd7cddfSDavid du Colombier {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
8387dd7cddfSDavid du Colombier };
8397dd7cddfSDavid du Colombier 
8407dd7cddfSDavid du Colombier /* Fill a rectangle specified by pointer into frame buffer, */
8417dd7cddfSDavid du Colombier /* starting bit within byte, width, and height. */
8427dd7cddfSDavid du Colombier /* Smashes rop->dest. */
8437dd7cddfSDavid du Colombier private void
fill_rectangle(register rop_ptr rop,int bit,int w,int color)8447dd7cddfSDavid du Colombier fill_rectangle(register rop_ptr rop, int bit, int w, int color)
8457dd7cddfSDavid du Colombier   /* rop: dest, draster, height */
8467dd7cddfSDavid du Colombier {
8477dd7cddfSDavid du Colombier     set_g_const(color);
8487dd7cddfSDavid du Colombier     set_g_const_map(0xf);
8497dd7cddfSDavid du Colombier     select_g_mask();
8507dd7cddfSDavid du Colombier     if (bit + w <= 8) {		/* Less than one byte */
8517dd7cddfSDavid du Colombier 	out_g_mask(rmask_tab[w] >> bit);
8527dd7cddfSDavid du Colombier 	memsetcol(rop);
8537dd7cddfSDavid du Colombier     } else {
8547dd7cddfSDavid du Colombier 	byte right_mask;
8557dd7cddfSDavid du Colombier 
8567dd7cddfSDavid du Colombier 	if (bit) {
8577dd7cddfSDavid du Colombier 	    out_g_mask(0xff >> bit);
8587dd7cddfSDavid du Colombier 	    memsetcol(rop);
8597dd7cddfSDavid du Colombier 	    rop->dest++;
8607dd7cddfSDavid du Colombier 	    w += bit - 8;
8617dd7cddfSDavid du Colombier 	}
8627dd7cddfSDavid du Colombier 	if (w >= 8) {
8637dd7cddfSDavid du Colombier 	    out_g_mask(0xff);	/* all bits */
8647dd7cddfSDavid du Colombier 	    rop->width = w >> 3;
8657dd7cddfSDavid du Colombier 	    memsetrect(rop);
8667dd7cddfSDavid du Colombier 	    rop->dest += rop->width;
8677dd7cddfSDavid du Colombier 	    w &= 7;
8687dd7cddfSDavid du Colombier 	}
8697dd7cddfSDavid du Colombier 	if ((right_mask = rmask_tab[w]) != 0) {
8707dd7cddfSDavid du Colombier 	    out_g_mask(right_mask);
8717dd7cddfSDavid du Colombier 	    memsetcol(rop);
8727dd7cddfSDavid du Colombier 	}
8737dd7cddfSDavid du Colombier     }
8747dd7cddfSDavid du Colombier     set_g_const_map(0);
8757dd7cddfSDavid du Colombier }
8767dd7cddfSDavid du Colombier 
8777dd7cddfSDavid du Colombier /* Fill a single row specified by pointer into frame buffer, */
8787dd7cddfSDavid du Colombier /* starting bit within byte, and width; clean up afterwards. */
8797dd7cddfSDavid du Colombier #define r_m_w(ptr) (*(ptr))++	/* read & write, data irrelevant */
8807dd7cddfSDavid du Colombier private void
fill_row_only(byte * dest,int bit,int w,int color)8817dd7cddfSDavid du Colombier fill_row_only(byte * dest, int bit, int w, int color)
8827dd7cddfSDavid du Colombier   /* rop: dest */
8837dd7cddfSDavid du Colombier {
8847dd7cddfSDavid du Colombier     if (bit + w <= 8) {		/* Less than one byte. */
8857dd7cddfSDavid du Colombier 	/* Optimize filling with black or white. */
8867dd7cddfSDavid du Colombier 	switch (color) {
8877dd7cddfSDavid du Colombier 	    case 0:
8887dd7cddfSDavid du Colombier 		set_g_mask(rmask_tab[w] >> bit);
8897dd7cddfSDavid du Colombier 		*dest &= color;	/* read, then write 0s; */
8907dd7cddfSDavid du Colombier 		/* some compilers optimize &= 0 to a store. */
8917dd7cddfSDavid du Colombier 		out_g_mask(0xff);	/* dot_end */
8927dd7cddfSDavid du Colombier 		break;
8937dd7cddfSDavid du Colombier 	    case 0xf:
8947dd7cddfSDavid du Colombier 		set_g_mask(rmask_tab[w] >> bit);
8957dd7cddfSDavid du Colombier 		*dest |= 0xff;	/* read, then write 1s; */
8967dd7cddfSDavid du Colombier 		/* some compilers optimize &= 0 to a store. */
8977dd7cddfSDavid du Colombier 		out_g_mask(0xff);	/* dot_end */
8987dd7cddfSDavid du Colombier 		break;
8997dd7cddfSDavid du Colombier 	    default:
9007dd7cddfSDavid du Colombier 		set_g_const(color);
9017dd7cddfSDavid du Colombier 		set_g_const_map(0xf);
9027dd7cddfSDavid du Colombier 		set_g_mask(rmask_tab[w] >> bit);
9037dd7cddfSDavid du Colombier 		r_m_w(dest);
9047dd7cddfSDavid du Colombier 		out_g_mask(0xff);	/* dot_end */
9057dd7cddfSDavid du Colombier 		set_g_const_map(0);
9067dd7cddfSDavid du Colombier 	}
9077dd7cddfSDavid du Colombier     } else {
9087dd7cddfSDavid du Colombier 	byte right_mask;
9097dd7cddfSDavid du Colombier 	int byte_count;
9107dd7cddfSDavid du Colombier 
9117dd7cddfSDavid du Colombier 	set_g_const(color);
9127dd7cddfSDavid du Colombier 	set_g_const_map(0xf);
9137dd7cddfSDavid du Colombier 	select_g_mask();
9147dd7cddfSDavid du Colombier 	if (bit) {
9157dd7cddfSDavid du Colombier 	    out_g_mask(0xff >> bit);
9167dd7cddfSDavid du Colombier 	    r_m_w(dest);
9177dd7cddfSDavid du Colombier 	    dest++;
9187dd7cddfSDavid du Colombier 	    w += bit - 8;
9197dd7cddfSDavid du Colombier 	}
9207dd7cddfSDavid du Colombier 	byte_count = w >> 3;
9217dd7cddfSDavid du Colombier 	if ((right_mask = rmask_tab[w & 7]) != 0) {
9227dd7cddfSDavid du Colombier 	    out_g_mask(right_mask);
9237dd7cddfSDavid du Colombier 	    r_m_w(dest + byte_count);
9247dd7cddfSDavid du Colombier 	}
9257dd7cddfSDavid du Colombier 	out_g_mask(0xff);
9267dd7cddfSDavid du Colombier 	if (byte_count) {
9277dd7cddfSDavid du Colombier 	    memset(dest, 0, byte_count);	/* data irrelevant */
9287dd7cddfSDavid du Colombier 	}
9297dd7cddfSDavid du Colombier 	set_g_const_map(0);
9307dd7cddfSDavid du Colombier     }
9317dd7cddfSDavid du Colombier }
932