xref: /plan9/sys/src/cmd/gs/src/gdevl256.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 2000 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: gdevl256.c,v 1.5 2002/02/21 22:24:51 giles Exp $ */
18 /* Ghostscript driver for 256-color VGA modes with Linux and vgalib */
19 /* This Driver was derived from the BGI-Driver. It was written
20    only for my own purpose. I never planned to release it or send
21    it to others. So, if something doesn't work, you may send
22    me a short note, but don't expect me to correct it. I will
23    try my very best, but i have some work to do.
24 
25    Ludger Kunz           |    ____________|Tel.: 02371/566-230
26    FernUniversitaet Hagen|   /| /   / \   |FAX:  02371/52212
27    Lehrgebiet ES         |  / |/   /_  \  |EMAIL:
28    Frauenstuhlweg 31     | /  |\  /     \ |ludger.kunz@fernuni-hagen.de
29    58644 Iserlohn        |/___|_\/_______\|
30  */
31 #include "memory_.h"
32 #include "gx.h"
33 #include "gxdevice.h"
34 #include "gserrors.h"
35 
36 #include <errno.h>
37 #include <vga.h>
38 #include <vgagl.h>
39 
40 /* The color map for dynamically assignable colors. */
41 #define first_dc_index 64
42 private int next_dc_index;
43 
44 #define dc_hash_size 293	/* prime, >num_dc */
45 typedef struct {
46     ushort rgb, index;
47 } dc_entry;
48 private dc_entry dynamic_colors[dc_hash_size + 1];
49 
50 #define XDPI   60		/* to get a more-or-less square aspect ratio */
51 #define YDPI   60
52 
53 #ifndef A4			/*Letter size */
54 #define YSIZE (20.0 * YDPI / 2.5)
55 #define XSIZE (8.5 / 11)*YSIZE	/* 8.5 x 11 inch page, by default */
56 #else /* A4 paper */
57 #define XSIZE 8.3		/*8.27 */
58 #define YSIZE 11.7		/*11.69 */
59 #endif
60 
61 
62 /* The device descriptor */
63 typedef struct gx_device_lvga256 {
64     gx_device_common;
65 } gx_device_lvga256;
66 
67 #define lvga256dev ((gx_device_lvga256 *)dev)
68 
69 private dev_proc_open_device(lvga256_open);
70 private dev_proc_close_device(lvga256_close);
71 private dev_proc_map_rgb_color(lvga256_map_rgb_color);
72 private dev_proc_map_color_rgb(lvga256_map_color_rgb);
73 private dev_proc_fill_rectangle(lvga256_fill_rectangle);
74 private dev_proc_tile_rectangle(lvga256_tile_rectangle);
75 private dev_proc_copy_mono(lvga256_copy_mono);
76 private dev_proc_copy_color(lvga256_copy_color);
77 private dev_proc_draw_line(lvga256_draw_line);
78 
79 private gx_device_procs lvga256_procs =
80 {
81     lvga256_open,
82     NULL,			/* get_initial_matrix */
83     NULL,			/* sync_output */
84     NULL,			/* output_page */
85     lvga256_close,
86     lvga256_map_rgb_color,
87     lvga256_map_color_rgb,
88     lvga256_fill_rectangle,
89     lvga256_tile_rectangle,
90     lvga256_copy_mono,
91     lvga256_copy_color,
92     lvga256_draw_line
93 };
94 
95 gx_device_lvga256 far_data gs_lvga256_device =
96 {std_device_color_body(gx_device_lvga256, &lvga256_procs, "lvga256",
97 		       0, 0,	/* width and height are set in lvga256_open */
98 		       1, 1,	/* density is set in lvga256_open */
99 		       /*dci_color( */ 8, 31, 4 /*) */ )
100 };
101 
102 /* Open the LINUX driver for graphics mode */
103 int
lvga256_open(gx_device * dev)104 lvga256_open(gx_device * dev)
105 {
106     int vgamode;
107     int width, height;
108 
109     vga_init();
110     vgamode = vga_getdefaultmode();
111     if (vgamode == -1)
112 	vgamode = G320x200x256;
113     vga_setmode(vgamode);
114     gl_setcontextvga(vgamode);
115     width = vga_getxdim();
116     height = vga_getydim();
117     dev->y_pixels_per_inch = height / 12.0;
118     dev->x_pixels_per_inch = dev->y_pixels_per_inch;
119     gx_device_set_width_height(dev, width, height);
120     {
121 	int c;
122 
123 	for (c = 0; c < 64; c++) {
124 	    static const byte c2[10] =
125 	    {0, 42, 0, 0, 0, 0, 0, 0, 21, 63};
126 
127 	    gl_setpalettecolor(c, c2[(c >> 2) & 9], c2[(c >> 1) & 9], c2[c & 9]);
128 	}
129     }
130     /* Initialize the dynamic color table. */
131     memset(dynamic_colors, 0, (dc_hash_size + 1) * sizeof(dc_entry));
132     next_dc_index = first_dc_index;
133 
134     return 0;
135 }
136 
137 /* Close the LINUX driver */
138 int
lvga256_close(gx_device * dev)139 lvga256_close(gx_device * dev)
140 {
141     vga_setmode(TEXT);
142     return 0;
143 }
144 
145 /* Map a r-g-b color to a palette index. */
146 /* The first 64 entries of the color map are set */
147 /* for compatibility with the older display modes: */
148 /* these are indexed as 0.0.R0.G0.B0.R1.G1.B1. */
149 gx_color_index
lvga256_map_rgb_color(gx_device * dev,gx_color_value r,gx_color_value g,gx_color_value b)150 lvga256_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
151 		      gx_color_value b)
152 {
153 #define cv_bits(v,n) (v >> (gx_color_value_bits - n))
154     ushort r5 = cv_bits(r, 5), g5 = cv_bits(g, 5), b5 = cv_bits(b, 5);
155     static const byte cube_bits[32] =
156     {0, 128, 128, 128, 128, 128, 128, 128, 128, 128,
157      8, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
158      1, 128, 128, 128, 128, 128, 128, 128, 128, 128,
159      9
160     };
161     uint cx = ((uint) cube_bits[r5] << 2) + ((uint) cube_bits[g5] << 1) +
162     (uint) cube_bits[b5];
163     ushort rgb;
164     register dc_entry *pdc;
165 
166     /* Check for a color on the cube. */
167     if (cx < 64)
168 	return (gx_color_index) cx;
169     /* Not on the cube, check the dynamic color table. */
170     rgb = (r5 << 10) + (g5 << 5) + b5;
171     for (pdc = &dynamic_colors[rgb % dc_hash_size]; pdc->rgb != 0; pdc++) {
172 	if (pdc->rgb == rgb)
173 	    return (gx_color_index) (pdc->index);
174     }
175     if (pdc == &dynamic_colors[dc_hash_size]) {		/* Wraparound */
176 	for (pdc = &dynamic_colors[0]; pdc->rgb != 0; pdc++) {
177 	    if (pdc->rgb == rgb)
178 		return (gx_color_index) (pdc->index);
179 	}
180     }
181     if (next_dc_index == 256) {	/* No space left, report failure. */
182 	return gx_no_color_index;
183     }
184     /* Not on the cube, and not in the dynamic table. */
185     /* Put in the dynamic table if space available. */
186     {
187 	int i = next_dc_index++;
188 
189 	pdc->rgb = rgb;
190 	pdc->index = i;
191 	gl_setpalettecolor(i, cv_bits(r, 6), cv_bits(g, 6), cv_bits(b, 6));
192 	return (gx_color_index) i;
193     }
194 }
195 
196 int
lvga256_map_color_rgb(gx_device * dev,gx_color_index color,unsigned short prgb[3])197 lvga256_map_color_rgb(gx_device * dev, gx_color_index color,
198 		      unsigned short prgb[3])
199 {
200 /*   gl_getpalettecolor (color,(int *)&prgb[0],(int *)&prgb[1],(int *)&prgb[2]); */
201     prgb[0] = gx_max_color_value;
202     prgb[1] = gx_max_color_value;
203     prgb[2] = gx_max_color_value;
204     return 0;
205 }
206 
207 /* Copy a monochrome bitmap.  The colors are given explicitly. */
208 /* Color = gx_no_color_index means transparent (no effect on the image). */
209 int
lvga256_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 zero,gx_color_index one)210 lvga256_copy_mono(gx_device * dev,
211 		const byte * base, int sourcex, int raster, gx_bitmap_id id,
212 		  int x, int y, int w, int h,
213 		  gx_color_index zero, gx_color_index one)
214 {
215     const byte *ptr_line = base + (sourcex >> 3);
216     int left_bit = 0x80 >> (sourcex & 7);
217     int dest_y = y, end_x = x + w;
218     int invert = 0;
219     int color;
220 
221     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
222     if (zero == gx_no_color_index) {
223 	if (one == gx_no_color_index)
224 	    return 0;
225 	color = (int)one;
226     } else {
227 	if (one == gx_no_color_index) {
228 	    color = (int)zero;
229 	    invert = -1;
230 	} else {		/* Pre-clear the rectangle to zero */
231 	    gl_fillbox(x, y, w, h, 0);
232 	    color = (int)one;
233 	}
234     }
235     while (h--) {		/* for each line */
236 	const byte *ptr_source = ptr_line;
237 	register int dest_x = x;
238 	register int bit = left_bit;
239 
240 	while (dest_x < end_x) {	/* for each bit in the line */
241 	    if ((*ptr_source ^ invert) & bit) {
242 		gl_setpixel(dest_x, dest_y, color);
243 	    }
244 	    dest_x++;
245 	    if ((bit >>= 1) == 0)
246 		bit = 0x80, ptr_source++;
247 	}
248 	dest_y++;
249 	ptr_line += raster;
250     }
251     return 0;
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 int
lvga256_copy_color(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)257 lvga256_copy_color(gx_device * dev,
258 		const byte * base, int sourcex, int raster, gx_bitmap_id id,
259 		   int x, int y, int w, int h)
260 {
261     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
262     if (gx_device_has_color(dev)) {	/* color device, four bits per pixel */
263 	const byte *line = base + sourcex;
264 
265 	gl_putbox(x, y, w, h, line);
266     } else {			/* monochrome device: one bit per pixel */
267 	/* bit map is the same as lvga256_copy_mono: one bit per pixel */
268 	lvga256_copy_mono(dev, base, sourcex, raster, id, x, y, w, h,
269 			  (gx_color_index) 0, (gx_color_index) 255);
270     }
271     return 0;
272 }
273 
274 /* Fill a rectangle. */
275 int
lvga256_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)276 lvga256_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
277 		       gx_color_index color)
278 {
279     fit_fill(dev, x, y, w, h);
280     gl_fillbox(x, y, w, h, color);
281     return 0;
282 }
283 
284 /* Tile a rectangle.  If neither color is transparent, */
285 /* pre-clear the rectangle to color0 and just tile with color1. */
286 /* This is faster because of how lvga256_copy_mono is implemented. */
287 /* Note that this also does the right thing for colored tiles. */
288 int
lvga256_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)289 lvga256_tile_rectangle(gx_device * dev, const gx_tile_bitmap * tile,
290       int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
291 		       int px, int py)
292 {
293     if (czero != gx_no_color_index && cone != gx_no_color_index) {
294 	lvga256_fill_rectangle(dev, x, y, w, h, czero);
295 	czero = gx_no_color_index;
296     }
297     return gx_default_tile_rectangle(dev, tile, x, y, w, h, czero, cone, px, py);
298 }
299 
300 /* Draw a line */
301 int
lvga256_draw_line(gx_device * dev,int x0,int y0,int x1,int y1,gx_color_index color)302 lvga256_draw_line(gx_device * dev, int x0, int y0, int x1, int y1,
303 		  gx_color_index color)
304 {
305     gl_line(x0, y0, x1, y1, color);
306     return 0;
307 }
308