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