xref: /plan9/sys/src/cmd/gs/src/gdevvglb.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 1993, 1994, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevvglb.c,v 1.5 2002/02/21 22:24:52 giles Exp $ */
18 /*
19  * This is a driver for 386 PCs using vgalib for graphics on the console
20  * display.  Note that this driver only works with 16-color modes.
21  *
22  * Written by Sigfrid Lundberg, siglun@euler.teorekol.lu.se.
23  * Modified by Erik Talvola, talvola@gnu.ai.mit.edu
24  * Updated 9/28/96 by L. Peter Deutsch, ghost@aladdin.com: allow setting
25  *   the display mode as a device parameter.
26  * Updated 2/13/97 by ghost@aladdin.com: make the device identify itself
27  *   as a page device.
28  * Updated 5/2/97 by ghost@aladdin.com: copy_mono computed some parameters
29  *   before doing fit_copy.
30  * Update 1997-06-28 by ghost@aladdin.com: get_bits wasn't implemented.
31  */
32 
33 #include "gx.h"
34 #include "gserrors.h"
35 #include "gsparam.h"
36 #include "gxdevice.h"
37 #include "gdevpccm.h"
38 
39 #include <errno.h>
40 #include <vga.h>
41 
42 typedef struct gx_device_vgalib {
43     gx_device_common;
44     int display_mode;
45 } gx_device_vgalib;
46 
47 #define vga_dev ((gx_device_vgalib *)dev)
48 
49 #define XDPI   60		/* to get a more-or-less square aspect ratio */
50 #define YDPI   60
51 
52 #ifndef A4			/*Letter size */
53 #define YSIZE (20.0 * YDPI / 2.5)
54 #define XSIZE (8.5 / 11)*YSIZE	/* 8.5 x 11 inch page, by default */
55 #else /* A4 paper */
56 #define XSIZE 8.27
57 #define YSIZE 11.69
58 #endif
59 
60 private dev_proc_open_device(vgalib_open);
61 private dev_proc_close_device(vgalib_close);
62 private dev_proc_map_rgb_color(vgalib_map_rgb_color);
63 private dev_proc_map_color_rgb(vgalib_map_color_rgb);
64 private dev_proc_fill_rectangle(vgalib_fill_rectangle);
65 private dev_proc_tile_rectangle(vgalib_tile_rectangle);
66 private dev_proc_copy_mono(vgalib_copy_mono);
67 private dev_proc_copy_color(vgalib_copy_color);
68 private dev_proc_get_bits(vgalib_get_bits);
69 private dev_proc_get_params(vgalib_get_params);
70 private dev_proc_put_params(vgalib_put_params);
71 
72 const gx_device_vgalib gs_vgalib_device =
73 {
74     std_device_std_body(gx_device_vgalib, 0, "vgalib",
75 			0, 0, 1, 1),
76     {vgalib_open,
77      NULL,			/* get_initial_matrix */
78      NULL,			/* sync_output */
79      NULL,			/* output_page */
80      vgalib_close,
81      vgalib_map_rgb_color,
82      vgalib_map_color_rgb,
83      vgalib_fill_rectangle,
84      vgalib_tile_rectangle,
85      vgalib_copy_mono,
86      vgalib_copy_color,
87      NULL,			/* draw_line (obsolete) */
88      vgalib_get_bits,
89      vgalib_get_params,
90      vgalib_put_params,
91      NULL,			/* map_cmyk_color */
92      NULL,			/* get_xfont_procs */
93      NULL,			/* get_xfont_device */
94      NULL,			/* map_rgb_alpha_color */
95      gx_page_device_get_page_device
96     },
97     -1				/* display_mode */
98 };
99 
100 private int
vgalib_open(gx_device * dev)101 vgalib_open(gx_device * dev)
102 {
103     int VGAMODE = vga_dev->display_mode;
104     int width = dev->width, height = dev->height;
105 
106     if (VGAMODE == -1)
107 	VGAMODE = vga_getdefaultmode();
108     if (VGAMODE == -1)
109 	vga_setmode(G640x480x16);
110     else
111 	vga_setmode(VGAMODE);
112     vga_clear();
113     if (width == 0)
114 	width = vga_getxdim() + 1;
115     if (height == 0)
116 	height = vga_getydim() + 1;
117 
118     /*vgalib provides no facilities for finding out aspect ratios */
119     if (dev->y_pixels_per_inch == 1) {
120 	dev->y_pixels_per_inch = height / 11.0;
121 	dev->x_pixels_per_inch = dev->y_pixels_per_inch;
122     }
123     gx_device_set_width_height(dev, width, height);
124 
125     /* Find out if the device supports color */
126     /* (default initialization is monochrome). */
127     /* We only recognize 16-color devices right now. */
128     if (vga_getcolors() > 1) {
129 	int index;
130 
131 	static const gx_device_color_info vgalib_16color = dci_pc_4bit;
132 
133 	dev->color_info = vgalib_16color;
134 
135 	for (index = 0; index < 16; ++index) {
136 	    gx_color_value rgb[3];
137 
138 	    (*dev_proc(dev, map_color_rgb)) (dev, (gx_color_index) index, rgb);
139 #define cv2pv(cv) ((cv) >> (gx_color_value_bits - 8))
140 	    vga_setpalette(index, cv2pv(rgb[0]), cv2pv(rgb[1]), cv2pv(rgb[2]));
141 #undef cv2pv
142 	}
143     }
144     return 0;
145 }
146 
147 private int
vgalib_close(gx_device * dev)148 vgalib_close(gx_device * dev)
149 {
150     vga_setmode(TEXT);
151     return 0;
152 }
153 
154 private gx_color_index
vgalib_map_rgb_color(gx_device * dev,gx_color_value red,gx_color_value green,gx_color_value blue)155 vgalib_map_rgb_color(gx_device * dev, gx_color_value red,
156 		     gx_color_value green, gx_color_value blue)
157 {
158     return pc_4bit_map_rgb_color(dev, red, green, blue);
159 }
160 
161 private int
vgalib_map_color_rgb(gx_device * dev,gx_color_index index,unsigned short rgb[3])162 vgalib_map_color_rgb(gx_device * dev, gx_color_index index,
163 		     unsigned short rgb[3])
164 {
165     return pc_4bit_map_color_rgb(dev, index, rgb);
166 }
167 
168 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)169 vgalib_tile_rectangle(gx_device * dev, const gx_tile_bitmap * tile,
170 		      int x, int y, int w, int h, gx_color_index czero,
171 		      gx_color_index cone, int px, int py)
172 {
173     if (czero != gx_no_color_index && cone != gx_no_color_index) {
174 	vgalib_fill_rectangle(dev, x, y, w, h, czero);
175 	czero = gx_no_color_index;
176     }
177     return gx_default_tile_rectangle(dev, tile, x, y, w, h, czero, cone, px,
178 				     py);
179 }
180 
181 private int
vgalib_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)182 vgalib_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
183 		      gx_color_index color)
184 {
185     int i, j;
186 
187     fit_fill(dev, x, y, w, h);
188     vga_setcolor((int)color);
189     if ((w | h) > 3) {		/* Draw larger rectangles as lines. */
190 	if (w > h)
191 	    for (i = y; i < y + h; ++i)
192 		vga_drawline(x, i, x + w - 1, i);
193 	else
194 	    for (j = x; j < x + w; ++j)
195 		vga_drawline(j, y, j, y + h - 1);
196     } else {			/* Draw small rectangles point-by-point. */
197 	for (i = y; i < y + h; i++)
198 	    for (j = x; j < x + w; j++)
199 		vga_drawpixel(j, i);
200     }
201     return 0;
202 }
203 
204 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)205 vgalib_copy_mono(gx_device * dev, const byte * base, int sourcex,
206 		 int raster, gx_bitmap_id id, int x, int y, int width,
207 		 int height, gx_color_index zero, gx_color_index one)
208 {
209     const byte *ptr_line;
210     int left_bit, dest_y, end_x;
211     int invert = 0;
212     int color;
213 
214     fit_copy(dev, base, sourcex, raster, id, x, y, width, height);
215     ptr_line = base + (sourcex >> 3);
216     left_bit = 0x80 >> (sourcex & 7);
217     dest_y = y, end_x = x + width;
218 
219     if (zero == gx_no_color_index) {
220 	if (one == gx_no_color_index)
221 	    return 0;
222 	color = (int)one;
223     } else {
224 	if (one == gx_no_color_index) {
225 	    color = (int)zero;
226 	    invert = -1;
227 	} else {		/* Pre-clear the rectangle to zero */
228 	    vgalib_fill_rectangle(dev, x, y, width, height, zero);
229 	    color = (int)one;
230 	}
231     }
232 
233     vga_setcolor(color);
234     while (height--) {		/* for each line */
235 	const byte *ptr_source = ptr_line;
236 	register int dest_x = x;
237 	register int bit = left_bit;
238 
239 	while (dest_x < end_x) {	/* for each bit in the line */
240 	    if ((*ptr_source ^ invert) & bit)
241 		vga_drawpixel(dest_x, dest_y);
242 	    dest_x++;
243 	    if ((bit >>= 1) == 0)
244 		bit = 0x80, ptr_source++;
245 	}
246 
247 	dest_y++;
248 	ptr_line += raster;
249     }
250     return 0;
251 }
252 
253 
254 /* Copy a color pixel map.  This is just like a bitmap, except that */
255 /* each pixel takes 4 bits instead of 1 when device driver has color. */
256 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)257 vgalib_copy_color(gx_device * dev, const byte * base, int sourcex,
258 		  int raster, gx_bitmap_id id, int x, int y,
259 		  int width, int height)
260 {
261 
262     fit_copy(dev, base, sourcex, raster, id, x, y, width, height);
263 
264     if (gx_device_has_color(dev)) {	/* color device, four bits per pixel */
265 	const byte *line = base + (sourcex >> 1);
266 	int dest_y = y, end_x = x + width;
267 
268 	if (width <= 0)
269 	    return 0;
270 	while (height--) {	/* for each line */
271 	    const byte *source = line;
272 	    register int dest_x = x;
273 
274 	    if (sourcex & 1) {	/* odd nibble first */
275 		int color = *source++ & 0xf;
276 
277 		vga_setcolor(color);
278 		vga_drawpixel(dest_x, dest_y);
279 		dest_x++;
280 	    }
281 	    /* Now do full bytes */
282 	    while (dest_x < end_x) {
283 		int color = *source >> 4;
284 
285 		vga_setcolor(color);
286 		vga_drawpixel(dest_x, dest_y);
287 		dest_x++;
288 
289 		if (dest_x < end_x) {
290 		    color = *source++ & 0xf;
291 		    vga_setcolor(color);
292 		    vga_drawpixel(dest_x, dest_y);
293 		    dest_x++;
294 		}
295 	    }
296 
297 	    dest_y++;
298 	    line += raster;
299 	}
300     } else {			/* monochrome device: one bit per pixel */
301 	/* bitmap is the same as bgi_copy_mono: one bit per pixel */
302 	vgalib_copy_mono(dev, base, sourcex, raster, id, x, y, width, height,
303 			 (gx_color_index) 0, (gx_color_index) 7);
304     }
305 
306     return 0;
307 }
308 
309 /* Read bits back from the device. */
310 private int
vgalib_get_bits(gx_device * dev,int y,byte * data,byte ** actual_data)311 vgalib_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
312 {
313     int x;
314     byte *dest = data;
315     int b = 0;
316     int depth = dev->color_info.depth;	/* 1 or 4 */
317     int mask = (1 << depth) - 1;
318     int left = 8;
319 
320     if (actual_data)
321 	*actual_data = data;
322     for (x = 0; x < dev->width; ++x) {
323 	int color = vga_getpixel(x, y);
324 
325 	if ((left -= depth) < 0)
326 	    *dest++ = b, b = 0, left += 8;
327 	b += (color & mask) << left;
328     }
329     if (left < 8)
330 	*dest = b;
331     return 0;
332 }
333 
334 /* Get/put the display mode parameter. */
335 private int
vgalib_get_params(gx_device * dev,gs_param_list * plist)336 vgalib_get_params(gx_device * dev, gs_param_list * plist)
337 {
338     int code = gx_default_get_params(dev, plist);
339 
340     if (code < 0)
341 	return code;
342     return param_write_int(plist, "DisplayMode", &vga_dev->display_mode);
343 }
344 private int
vgalib_put_params(gx_device * dev,gs_param_list * plist)345 vgalib_put_params(gx_device * dev, gs_param_list * plist)
346 {
347     int ecode = 0;
348     int code;
349     int imode = vga_dev->display_mode;
350     const char *param_name;
351 
352     switch (code = param_read_int(plist, (param_name = "DisplayMode"), &imode)) {
353 	default:
354 	    ecode = code;
355 	    param_signal_error(plist, param_name, ecode);
356 	case 0:
357 	case 1:
358 	    break;
359     }
360 
361     if (ecode < 0)
362 	return ecode;
363     code = gx_default_put_params(dev, plist);
364     if (code < 0)
365 	return code;
366 
367     if (imode != vga_dev->display_mode) {
368 	if (dev->is_open)
369 	    gs_closedevice(dev);
370 	vga_dev->display_mode = imode;
371     }
372     return 0;
373 }
374