/* Copyright (C) 1992, 1993, 1994, 1996, 1997, 1998, 1999 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevvglb.c,v 1.3.6.1.2.1 2003/01/17 00:49:02 giles Exp $ */ /* * This is a driver for 386 PCs using vgalib for graphics on the console * display. Note that this driver only works with 16-color modes. * * Written by Sigfrid Lundberg, siglun@euler.teorekol.lu.se. * Modified by Erik Talvola, talvola@gnu.ai.mit.edu * Updated 9/28/96 by L. Peter Deutsch, ghost@aladdin.com: allow setting * the display mode as a device parameter. * Updated 2/13/97 by ghost@aladdin.com: make the device identify itself * as a page device. * Updated 5/2/97 by ghost@aladdin.com: copy_mono computed some parameters * before doing fit_copy. * Update 1997-06-28 by ghost@aladdin.com: get_bits wasn't implemented. */ #include "gx.h" #include "gserrors.h" #include "gsparam.h" #include "gxdevice.h" #include "gdevpccm.h" #include #include typedef struct gx_device_vgalib { gx_device_common; int display_mode; } gx_device_vgalib; #define vga_dev ((gx_device_vgalib *)dev) #define XDPI 60 /* to get a more-or-less square aspect ratio */ #define YDPI 60 #ifndef A4 /*Letter size */ #define YSIZE (20.0 * YDPI / 2.5) #define XSIZE (8.5 / 11)*YSIZE /* 8.5 x 11 inch page, by default */ #else /* A4 paper */ #define XSIZE 8.27 #define YSIZE 11.69 #endif private dev_proc_open_device(vgalib_open); private dev_proc_close_device(vgalib_close); private dev_proc_map_rgb_color(vgalib_map_rgb_color); private dev_proc_map_color_rgb(vgalib_map_color_rgb); private dev_proc_fill_rectangle(vgalib_fill_rectangle); private dev_proc_tile_rectangle(vgalib_tile_rectangle); private dev_proc_copy_mono(vgalib_copy_mono); private dev_proc_copy_color(vgalib_copy_color); private dev_proc_get_bits(vgalib_get_bits); private dev_proc_get_params(vgalib_get_params); private dev_proc_put_params(vgalib_put_params); const gx_device_vgalib gs_vgalib_device = { std_device_std_body(gx_device_vgalib, 0, "vgalib", 0, 0, 1, 1), {vgalib_open, NULL, /* get_initial_matrix */ NULL, /* sync_output */ NULL, /* output_page */ vgalib_close, vgalib_map_rgb_color, vgalib_map_color_rgb, vgalib_fill_rectangle, vgalib_tile_rectangle, vgalib_copy_mono, vgalib_copy_color, NULL, /* draw_line (obsolete) */ vgalib_get_bits, vgalib_get_params, vgalib_put_params, NULL, /* map_cmyk_color */ NULL, /* get_xfont_procs */ NULL, /* get_xfont_device */ NULL, /* map_rgb_alpha_color */ gx_page_device_get_page_device }, -1 /* display_mode */ }; private int vgalib_open(gx_device * dev) { int VGAMODE = vga_dev->display_mode; int width = dev->width, height = dev->height; if (VGAMODE == -1) VGAMODE = vga_getdefaultmode(); if (VGAMODE == -1) vga_setmode(G640x480x16); else vga_setmode(VGAMODE); vga_clear(); if (width == 0) width = vga_getxdim() + 1; if (height == 0) height = vga_getydim() + 1; /*vgalib provides no facilities for finding out aspect ratios */ if (dev->y_pixels_per_inch == 1) { dev->y_pixels_per_inch = height / 11.0; dev->x_pixels_per_inch = dev->y_pixels_per_inch; } gx_device_set_width_height(dev, width, height); /* Find out if the device supports color */ /* (default initialization is monochrome). */ /* We only recognize 16-color devices right now. */ if (vga_getcolors() > 1) { int index; static const gx_device_color_info vgalib_16color = dci_pc_4bit; dev->color_info = vgalib_16color; for (index = 0; index < 16; ++index) { gx_color_value rgb[3]; (*dev_proc(dev, map_color_rgb)) (dev, (gx_color_index) index, rgb); #define cv2pv(cv) ((cv) >> (gx_color_value_bits - 8)) vga_setpalette(index, cv2pv(rgb[0]), cv2pv(rgb[1]), cv2pv(rgb[2])); #undef cv2pv } } return 0; } private int vgalib_close(gx_device * dev) { vga_setmode(TEXT); return 0; } private gx_color_index vgalib_map_rgb_color(gx_device * dev, gx_color_value red, gx_color_value green, gx_color_value blue) { return pc_4bit_map_rgb_color(dev, red, green, blue); } private int vgalib_map_color_rgb(gx_device * dev, gx_color_index index, unsigned short rgb[3]) { return pc_4bit_map_color_rgb(dev, index, rgb); } private int vgalib_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) { if (czero != gx_no_color_index && cone != gx_no_color_index) { vgalib_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); } private int vgalib_fill_rectangle(gx_device * dev, int x, int y, int w, int h, gx_color_index color) { int i, j; fit_fill(dev, x, y, w, h); vga_setcolor((int)color); if ((w | h) > 3) { /* Draw larger rectangles as lines. */ if (w > h) for (i = y; i < y + h; ++i) vga_drawline(x, i, x + w - 1, i); else for (j = x; j < x + w; ++j) vga_drawline(j, y, j, y + h - 1); } else { /* Draw small rectangles point-by-point. */ for (i = y; i < y + h; i++) for (j = x; j < x + w; j++) vga_drawpixel(j, i); } return 0; } private int vgalib_copy_mono(gx_device * dev, const byte * base, int sourcex, int raster, gx_bitmap_id id, int x, int y, int width, int height, gx_color_index zero, gx_color_index one) { const byte *ptr_line; int left_bit, dest_y, end_x; int invert = 0; int color; fit_copy(dev, base, sourcex, raster, id, x, y, width, height); ptr_line = base + (sourcex >> 3); left_bit = 0x80 >> (sourcex & 7); dest_y = y, end_x = x + width; 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 */ vgalib_fill_rectangle(dev, x, y, width, height, zero); color = (int)one; } } vga_setcolor(color); while (height--) { /* for each line */ const 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) vga_drawpixel(dest_x, dest_y); 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. */ private int vgalib_copy_color(gx_device * dev, const byte * base, int sourcex, int raster, gx_bitmap_id id, int x, int y, int width, int height) { fit_copy(dev, base, sourcex, raster, id, x, y, width, height); if (gx_device_has_color(dev)) { /* color device, four bits per pixel */ const byte *line = base + (sourcex >> 1); int dest_y = y, end_x = x + width; if (width <= 0) return 0; while (height--) { /* for each line */ const byte *source = line; register int dest_x = x; if (sourcex & 1) { /* odd nibble first */ int color = *source++ & 0xf; vga_setcolor(color); vga_drawpixel(dest_x, dest_y); dest_x++; } /* Now do full bytes */ while (dest_x < end_x) { int color = *source >> 4; vga_setcolor(color); vga_drawpixel(dest_x, dest_y); dest_x++; if (dest_x < end_x) { color = *source++ & 0xf; vga_setcolor(color); vga_drawpixel(dest_x, dest_y); 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 */ vgalib_copy_mono(dev, base, sourcex, raster, id, x, y, width, height, (gx_color_index) 0, (gx_color_index) 7); } return 0; } /* Read bits back from the device. */ private int vgalib_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data) { int x; byte *dest = data; int b = 0; int depth = dev->color_info.depth; /* 1 or 4 */ int mask = (1 << depth) - 1; int left = 8; if (actual_data) *actual_data = data; for (x = 0; x < dev->width; ++x) { int color = vga_getpixel(x, y); if ((left -= depth) < 0) *dest++ = b, b = 0, left += 8; b += (color & mask) << left; } if (left < 8) *dest = b; return 0; } /* Get/put the display mode parameter. */ private int vgalib_get_params(gx_device * dev, gs_param_list * plist) { int code = gx_default_get_params(dev, plist); if (code < 0) return code; return param_write_int(plist, "DisplayMode", &vga_dev->display_mode); } private int vgalib_put_params(gx_device * dev, gs_param_list * plist) { int ecode = 0; int code; int imode = vga_dev->display_mode; const char *param_name; switch (code = param_read_int(plist, (param_name = "DisplayMode"), &imode)) { default: ecode = code; param_signal_error(plist, param_name, ecode); case 0: case 1: break; } if (ecode < 0) return ecode; code = gx_default_put_params(dev, plist); if (code < 0) return code; if (imode != vga_dev->display_mode) { if (dev->is_open) gs_closedevice(dev); vga_dev->display_mode = imode; } return 0; }