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