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