home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved.
- Distributed by Free Software Foundation, Inc.
-
- This file is part of Ghostscript.
-
- Ghostscript is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
- to anyone for the consequences of using it or for whether it serves any
- particular purpose or works at all, unless he says so in writing. Refer
- to the Ghostscript General Public License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- Ghostscript, but only under the conditions described in the Ghostscript
- General Public License. A copy of this license is supposed to have been
- given to you along with Ghostscript so you can know your rights and
- responsibilities. It should be in a file named COPYING. Among other
- things, the copyright notice and this notice must be preserved on all
- copies. */
-
- /* gdevbgi.c */
- /* Ghostscript driver for Borland Graphics Interface (BGI) */
- #include <string.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <graphics.h>
- #include "gx.h"
- #include "gsmatrix.h" /* for gxdevice.h */
- #include "gxbitmap.h"
- #include "gxdevice.h"
-
- /*
- * BGI supports these video cards:
- * Hercules, CGA, MCGA, EGA, VGA, AT&T 400, IBM 8514, PC3270.
- * Highest resolution mode is used with all these video cards.
- * EGA and VGA display 16 colors, the rest are black-and-white only.
- * In addition, the environment variable BGIUSER may be used
- * to define a user-supplied Super VGA driver: see the use.doc file
- * for details.
- */
- #define SUPER_VGA 999 /* bogus # for user-defined driver */
-
- /* See gxdevice.h for the definitions of the procedures. */
-
- dev_proc_open_device(bgi_open);
- dev_proc_close_device(bgi_close);
- dev_proc_map_rgb_color(bgi_map_rgb_color);
- dev_proc_map_color_rgb(bgi_map_color_rgb);
- dev_proc_fill_rectangle(bgi_fill_rectangle);
- dev_proc_tile_rectangle(bgi_tile_rectangle);
- dev_proc_copy_mono(bgi_copy_mono);
- dev_proc_copy_color(bgi_copy_color);
- dev_proc_draw_line(bgi_draw_line);
- dev_proc_fill_trapezoid(bgi_fill_trapezoid);
-
- /* The device descriptor */
- typedef struct gx_device_bgi_s gx_device_bgi;
- struct gx_device_bgi_s {
- gx_device_common;
- int display_mode;
- struct text_info text_mode;
- };
- #define bgi_dev ((gx_device_bgi *)dev)
- static gx_device_procs bgi_procs = {
- bgi_open,
- gx_default_get_initial_matrix,
- gx_default_sync_output,
- gx_default_output_page,
- bgi_close,
- bgi_map_rgb_color,
- bgi_map_color_rgb,
- bgi_fill_rectangle,
- bgi_tile_rectangle,
- bgi_copy_mono,
- bgi_copy_color,
- bgi_draw_line,
- bgi_fill_trapezoid,
- gx_default_tile_trapezoid
- };
- gx_device_bgi gs_bgi_device = {
- sizeof(gx_device_bgi),
- &bgi_procs,
- "bgi",
- 0, 0, /* width and height are set in bgi_open */
- 0, 0, /* density is set in bgi_open */
- no_margins,
- 0, /* has_color, set for monochrome device */
- 1, /* max_rgb_value, set for monochrome */
- 1, /* bits per color pixel, set for monochrome */
- 0 /* not open yet */
- };
-
- /* Detection procedure for user-defined driver. */
- private int huge
- detectVGA()
- { return gs_bgi_device.display_mode;
- }
-
- /* Open the BGI driver for graphics mode */
- int
- bgi_open(gx_device *dev)
- { int driver, mode;
- char *bgi_user = getenv("BGIUSER");
- char *bgi_path = getenv("BGIPATH");
-
- gettextinfo(&bgi_dev->text_mode);
-
- if ( bgi_path == NULL )
- bgi_path = "";
- if ( bgi_user != NULL )
- { /* A user-supplied driver is specified as "mode.dname", */
- /* where mode is a hex number and dname is the name */
- /* of the driver file. */
- char dname[40];
- if ( strlen(bgi_user) > sizeof(dname) ||
- sscanf(bgi_user, "%x.%s", &mode, dname) != 2
- )
- { eprintf("BGIUSER not in form nn.dname.\n");
- exit(1);
- }
- gs_bgi_device.display_mode = mode; /* sigh.... */
- installuserdriver(dname, detectVGA);
- driver = DETECT;
- initgraph(&driver, &mode, bgi_path);
- driver = SUPER_VGA;
- }
- else /* not user-defined driver */
- { /* We include the EGA/VGA driver in the Ghostscript */
- /* executable, so end-users don't have to have */
- /* the BGI files. */
- if ( registerbgidriver(EGAVGA_driver) < 0 )
- { eprintf("BGI: Can't register EGA/VGA driver!\n");
- exit(1);
- }
-
- detectgraph(&driver, &mode);
- if ( driver < 0 )
- { eprintf("BGI: No graphics hardware detected!\n");
- exit(1);
- }
-
- if ( driver == EGA64 )
- { /* Select 16 color video mode if video card is EGA with 64 Kb of memory */
- mode = EGA64LO;
- }
-
- /* Initialize graphics mode. */
-
- /* Following patch for AT&T 6300 is courtesy of */
- /* Allan Wax, Xerox Corp. */
- if ( driver == CGA )
- { /* The actual hardware might be an AT&T 6300. */
- /* Try initializing it that way. */
- int save_mode = mode;
- driver = ATT400, mode = ATT400HI;
- initgraph(&driver, &mode, bgi_path);
- if ( graphresult() != grOk )
- { /* Nope, it was a real CGA. */
- closegraph();
- driver = CGA, mode = save_mode;
- initgraph(&driver, &mode, bgi_path);
- }
- }
- else
- initgraph(&driver, &mode, "");
- }
-
- { int code = graphresult();
- if ( code != grOk )
- { eprintf1("Error initializing BGI driver: %s\n",
- grapherrormsg(code));
- exit(1);
- }
- }
-
- /* Set parameters that were unknown before opening device */
-
- /* Size and nominal density of screen. */
- /* The following algorithm maps an appropriate fraction of */
- /* the display screen to an 8.5" x 11" coordinate space. */
- /* This may or may not be what is desired! */
- dev->width = getmaxx() + 1;
- dev->height = getmaxy() + 1;
- dev->y_pixels_per_inch = dev->height / 11.0;
- { /* Make an educated guess about the aspect ratio. */
- float aspect_ratio;
- switch ( dev->height )
- {
- case 200: case 400:
- aspect_ratio = 25.0 / 11.0;
- break;
- case 350:
- aspect_ratio = 48.0 / 35.0;
- break;
- default: /* assume square pixels */
- aspect_ratio = 1;
- }
- if ( dev->width / dev->height >= 2 )
- aspect_ratio *= 2;
- dev->x_pixels_per_inch = dev->height * aspect_ratio / 11.0;
- }
-
- /* Find out if the device supports color */
- /* (default initialization is BLACK and WHITE) */
- switch ( driver )
- {
- case EGA:
- case EGA64:
- case VGA:
- case SUPER_VGA:
- dev->has_color = 1;
- dev->bits_per_color_pixel = 4;
- dev->max_rgb_value = 2;
- }
- return 0;
- }
-
-
- /* Close the BGI driver */
- int
- bgi_close(gx_device *dev)
- { closegraph();
- textmode(bgi_dev->text_mode.currmode);
- return 0;
- }
-
-
- /* Map a r-g-b color to the 16 colors available with an EGA/VGA video card. */
- /* r, g, b are between 0 and 2. */
- static char rgb_color[3][3][3] =
- { { { BLACK, BLUE, LIGHTBLUE },
- { GREEN, CYAN, LIGHTCYAN },
- { LIGHTGREEN, LIGHTCYAN, LIGHTCYAN } },
- { { RED, MAGENTA, LIGHTMAGENTA },
- { BROWN, LIGHTGRAY, LIGHTBLUE },
- { YELLOW, YELLOW, WHITE } },
- { { LIGHTRED, LIGHTMAGENTA, LIGHTMAGENTA },
- { YELLOW, YELLOW, LIGHTMAGENTA },
- { YELLOW, YELLOW, WHITE } }
- };
-
- gx_color_index
- bgi_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
- { if ( dev->has_color )
- { return (gx_color_index)rgb_color[r][g][b];
- }
- else
- { if ( r > 0 || g > 0 || b > 0 )
- return (gx_color_index)WHITE;
- else
- return (gx_color_index)BLACK;
- }
- }
-
-
- /* Map a color code to r-g-b. Surprisingly enough, this is algorithmic. */
- int
- bgi_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
- { int on = (color & 8 ? 2 : 1);
- prgb[0] = (color & 4 ? on : 0);
- prgb[1] = (color & 2 ? on : 0);
- prgb[2] = (color & 1 ? on : 0);
- return 0;
- }
-
-
- /* Copy a monochrome bitmap. The colors are given explicitly. */
- /* Color = gx_no_color_index means transparent (no effect on the image). */
- int
- bgi_copy_mono(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h,
- gx_color_index zero, gx_color_index one)
- { byte *ptr_line = base + (sourcex >> 3);
- int left_bit = 0x80 >> (sourcex & 7);
- int dest_y = y, end_x = x + w;
- int invert = 0;
- int color;
-
- if ( zero == gx_no_color_index )
- { if ( one == gx_no_color_index ) return 0;
- color = (int)one;
- }
- else
- { if ( one == gx_no_color_index )
- { color = (int)zero;
- invert = -1;
- }
- else
- { /* Pre-clear the rectangle to zero */
- setfillstyle(SOLID_FILL, (int)zero);
- bar(x, y, x + w - 1, y + h - 1);
- color = (int)one;
- }
- }
-
- while ( h-- ) /* for each line */
- { byte *ptr_source = ptr_line;
- register int dest_x = x;
- register int bit = left_bit;
- while ( dest_x < end_x ) /* for each bit in the line */
- { if ( (*ptr_source ^ invert) & bit )
- putpixel(dest_x, dest_y, color);
- dest_x++;
- if ( (bit >>= 1) == 0 )
- bit = 0x80, ptr_source++;
- }
- dest_y++;
- ptr_line += raster;
- }
- return 0;
- }
-
-
- /* Copy a color pixel map. This is just like a bitmap, except that */
- /* each pixel takes 4 bits instead of 1 when device driver has color. */
- int
- bgi_copy_color(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h)
- { if ( dev->has_color )
- { /* color device, four bits per pixel */
- byte *line = base + (sourcex >> 1);
- int dest_y = y, end_x = x + w;
-
- if ( w <= 0 ) return 0;
- while ( h-- ) /* for each line */
- { byte *source = line;
- register int dest_x = x;
- if ( sourcex & 1 ) /* odd nibble first */
- { int color = *source++ & 0xf;
- putpixel(dest_x, dest_y, color);
- dest_x++;
- }
- /* Now do full bytes */
- while ( dest_x < end_x )
- { int color = *source >> 4;
- putpixel(dest_x, dest_y, color);
- dest_x++;
- if ( dest_x < end_x )
- { color = *source++ & 0xf;
- putpixel(dest_x, dest_y, color);
- dest_x++;
- }
- }
- dest_y++;
- line += raster;
- }
- }
- else /* monochrome device: one bit per pixel */
- { /* bitmap is the same as bgi_copy_mono: one bit per pixel */
- bgi_copy_mono(dev, base, sourcex, raster, x, y, w, h,
- (gx_color_index)BLACK, (gx_color_index)WHITE);
- }
- return 0;
- }
-
-
- /* Fill a rectangle. */
- int
- bgi_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
- gx_color_index color)
- { setfillstyle(SOLID_FILL, (int)color);
- bar(x, y, x + w - 1, y + h - 1);
- return 0;
- }
-
-
- /* Tile a rectangle. If neither color is transparent, */
- /* pre-clear the rectangle to color0 and just tile with color1. */
- /* This is faster because of how bgi_copy_mono is implemented. */
- /* Note that this also does the right thing for colored tiles. */
- int
- bgi_tile_rectangle(gx_device *dev, gx_bitmap *tile,
- int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
- int px, int py)
- { if ( czero != gx_no_color_index && cone != gx_no_color_index )
- { bgi_fill_rectangle(dev, x, y, w, h, czero);
- czero = gx_no_color_index;
- }
- return gx_default_tile_rectangle(dev, tile, x, y, w, h, czero, cone, px, py);
- }
-
-
- /* Draw a line */
- int
- bgi_draw_line(gx_device *dev, int x0, int y0, int x1, int y1,
- gx_color_index color)
- { setcolor((int)color);
- setlinestyle(SOLID_LINE, 0, NORM_WIDTH); /* solid, one pixel wide */
- line(x0, y0, x1, y1);
- return 0;
- }
-
-
- /* Fill a trapezoid */
- int
- bgi_fill_trapezoid(gx_device *dev, int x0, int y0, int width0,
- int x1, int y1, int width1, gx_color_index color)
- { struct pointtype pts[4];
- setcolor((int)color);
- /* We'd like to suppress the border, but */
- /* there is no way to do it (aaargh!). */
- setlinestyle(SOLID_LINE, 0, NORM_WIDTH); /* border solid, one pixel wide */
- setfillstyle(SOLID_FILL, color);
- --y1, --width0, --width1; /* BGI uses closed intervals */
- pts[0].x = x0; pts[0].y = y0;
- pts[1].x = x1; pts[1].y = y1;
- pts[2].x = x1 + width1; pts[2].y = y1;
- pts[3].x = x0 + width0; pts[3].y = y0;
- fillpoly(4, (int *)pts);
- return 0;
- }
-