1 /* Framebuffer Graphics Libary for Linux, Copyright 1993 Harm Hanemaayer */
2 /* grlib.c      Main module */
3 
4 
5 #include <stdlib.h>
6 #include <vga.h>
7 #include "inlstring.h"		/* include inline string operations */
8 
9 #include "vgagl.h"
10 #include "def.h"
11 #include "driver.h"
12 
13 
14 /* Global variables */
15 
16 #ifdef DLL_CONTEXT_SHADOW
17 
18 /* The current context variable is shadowed in a read-only variable for */
19 /* external use. */
20 
21 GraphicsContext __currentcontext;	/* Internal current context. */
22 GraphicsContext currentcontext;	/* Copy for external use. */
23 
24 #else
25 
26 GraphicsContext currentcontext;
27 
28 #endif
29 
30 void (*__svgalib_nonaccel_fillbox)(int, int, int, int, int);
31 static int screenoffset = 0;	/* Used by copy(box)toscreen. */
32 
33 
34 /* Framebuffer function pointers */
35 
36 static framebufferfunctions ff8 =
37 {
38     __svgalib_driver8_setpixel,
39     __svgalib_driver8_getpixel,
40     __svgalib_driver8_hline,
41     __svgalib_driver8_fillbox,
42     __svgalib_driver8_putbox,
43     __svgalib_driver8_getbox,
44     __svgalib_driver8_putboxmask,
45     __svgalib_driver8_putboxpart,
46     __svgalib_driver8_getboxpart,
47     __svgalib_driver8_copybox
48 };
49 
50 static framebufferfunctions ff16 =
51 {
52     __svgalib_driver16_setpixel,
53     __svgalib_driver16_getpixel,
54     __svgalib_driver16_hline,
55     __svgalib_driver16_fillbox,
56     __svgalib_driver16_putbox,
57     __svgalib_driver16_getbox,
58     __svgalib_driver16_putboxmask,
59     __svgalib_driver16_putboxpart,
60     __svgalib_driver16_getboxpart,
61     __svgalib_driver16_copybox
62 };
63 
64 static framebufferfunctions ff24 =
65 {
66     __svgalib_driver24_setpixel,
67     __svgalib_driver24_getpixel,
68     __svgalib_driver24_hline,
69     __svgalib_driver24_fillbox,
70     __svgalib_driver24_putbox,
71     __svgalib_driver24_getbox,
72     __svgalib_driver24_putboxmask,
73     __svgalib_driver24_putboxpart,
74     __svgalib_driver24_getboxpart,
75     __svgalib_driver24_copybox
76 };
77 
78 static framebufferfunctions ff32 =
79 {
80     __svgalib_driver32_setpixel,
81     __svgalib_driver32_getpixel,
82     __svgalib_driver32_hline,
83     __svgalib_driver32_fillbox,
84     __svgalib_driver32_putbox,
85     __svgalib_driver32_getbox,
86     __svgalib_driver32_putboxmask,
87     __svgalib_driver32_putboxpart,
88     __svgalib_driver32_getboxpart,
89     __svgalib_driver32_copybox
90 };
91 
92 static framebufferfunctions ff8paged =
93 {
94     __svgalib_driver8p_setpixel,
95     __svgalib_driver8p_getpixel,
96     __svgalib_driver8p_hline,
97     __svgalib_driver8p_fillbox,
98     __svgalib_driver8p_putbox,
99     __svgalib_driver8p_getbox,
100     __svgalib_driver8p_putboxmask,
101     __svgalib_driver8p_putboxpart,
102     __svgalib_driver8p_getboxpart,
103     __svgalib_driver8p_copybox
104 };
105 
106 static framebufferfunctions ff16paged =
107 {
108     __svgalib_driver16p_setpixel,
109     __svgalib_driver16p_getpixel,
110     __svgalib_driver16p_hline,
111     __svgalib_driver16p_fillbox,
112     __svgalib_driver16p_putbox,
113     __svgalib_driver16p_getbox,
114     __svgalib_driver16p_putboxmask,
115     __svgalib_driver16p_putboxpart,
116     __svgalib_driver16p_getboxpart,
117     __svgalib_driver16p_copybox
118 };
119 
120 static framebufferfunctions ff24paged =
121 {
122     __svgalib_driver24p_setpixel,
123     __svgalib_driver24p_getpixel,
124     __svgalib_driver24p_hline,
125     __svgalib_driver24p_fillbox,
126     __svgalib_driver24p_putbox,
127     __svgalib_driver24p_getbox,
128     __svgalib_driver24p_putboxmask,
129     __svgalib_driver24p_putboxpart,
130     __svgalib_driver24p_getboxpart,
131     __svgalib_driver24p_copybox
132 };
133 
134 static framebufferfunctions ff32paged =
135 {
136     __svgalib_driver32p_setpixel,
137     __svgalib_driver32p_getpixel,
138     __svgalib_driver32p_hline,
139     __svgalib_driver32p_fillbox,
140     __svgalib_driver32p_putbox,
141     __svgalib_driver32p_getbox,
142     __svgalib_driver32p_putboxmask,
143     __svgalib_driver32p_putboxpart,
144     __svgalib_driver32p_getboxpart,
145     __svgalib_driver32p_copybox
146 };
147 
148 static framebufferfunctions ffplanar256 =
149 {
150     (void *) __svgalib_driverplanar256_nothing,
151     (void *) __svgalib_driverplanar256_nothing,
152     (void *) __svgalib_driverplanar256_nothing,
153     (void *) __svgalib_driverplanar256_nothing,
154     __svgalib_driverplanar256_putbox,
155     (void *) __svgalib_driverplanar256_nothing,
156     (void *) __svgalib_driverplanar256_nothing,
157     (void *) __svgalib_driverplanar256_nothing,
158     (void *) __svgalib_driverplanar256_nothing,
159     (void *) __svgalib_driverplanar256_nothing,
160 };
161 
162 #if 0				/* Not yet used */
163 static framebufferfunctions ffplanar16 =
164 {
165     (void *) __svgalib_driverplanar16_nothing,
166     (void *) __svgalib_driverplanar16_nothing,
167     (void *) __svgalib_driverplanar16_nothing,
168     (void *) __svgalib_driverplanar16_nothing,
169     (void *) __svgalib_driverplanar16_nothing,
170     (void *) __svgalib_driverplanar16_nothing,
171     (void *) __svgalib_driverplanar16_nothing,
172     (void *) __svgalib_driverplanar16_nothing,
173     (void *) __svgalib_driverplanar16_nothing,
174     (void *) __svgalib_driverplanar16_nothing,
175 };
176 #endif
177 
178 
179 /* Initialization and graphics contexts */
180 
181 #define SCREENSIZE(gc) ((gc).bytewidth * (gc).height)
182 
colorbits(int c)183 static int colorbits(int c)
184 {
185     switch (c) {
186     default:
187     case 256:
188 	return 8;
189     case 32768:
190 	return 15;
191     case 65536:
192 	return 16;
193     case 256 * 65536:
194 	return 24;
195     }
196 }
197 
gl_setcontextvga(int m)198 int gl_setcontextvga(int m)
199 {
200     framebufferfunctions *ff;
201     vga_modeinfo *modeinfo;
202     int accelfuncs;
203     if (!vga_hasmode(m))
204 	return -1;
205     modeinfo = vga_getmodeinfo(m);
206     /* Set graphics context */
207     WIDTH = modeinfo->width;
208     HEIGHT = modeinfo->height;
209     BYTESPERPIXEL = modeinfo->bytesperpixel;
210     COLORS = modeinfo->colors;
211     BITSPERPIXEL = colorbits(COLORS);
212     BYTEWIDTH = modeinfo->linewidth;
213     VBUF = vga_getgraphmem();
214     MODEFLAGS = 0;
215     __clip = 0;
216     ff = &(__currentcontext.ff);
217     if (modeinfo->flags & IS_MODEX) {
218 	/* Pretend it's a regular (linear) context. */
219 	BYTESPERPIXEL = 1;
220 	BYTEWIDTH *= 4;
221 	MODETYPE = CONTEXT_MODEX;
222 	if (BYTEWIDTH * HEIGHT * 2 <= 256 * 1024)
223 	    MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
224 	if (BYTEWIDTH * HEIGHT * 3 <= 256 * 1024)
225 	    MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
226 	__currentcontext.ff = ffplanar256;
227     } else if (modeinfo->colors == 16) {
228 	/* Pretend it's a regular one byte per pixel context. */
229 	BYTESPERPIXEL = 1;
230 	BYTEWIDTH *= 8;
231 	MODETYPE = CONTEXT_PLANAR16;
232 	if (BYTEWIDTH * HEIGHT <= 256 * 1024)
233 	    MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
234 	if (BYTEWIDTH * HEIGHT * 3 / 2 <= 256 * 1024)
235 	    MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
236     } else if ((m == G320x200x256 && modeinfo->maxpixels <= 65536) ||
237 	       (modeinfo->flags & IS_LINEAR)
238 #if 0				/* svgalib doesn't VT-switch correctly with linear addressing. */
239 	       || ((modeinfo->flags & CAPABLE_LINEAR)
240 	/* Creepy. Try linear addressing only if the mode is set. */
241 	&& vga_getcurrentmode() == m && (vga_setlinearaddressing() != -1))
242 #endif
243 	) {
244 	/* No banking. */
245 	/* Get get the fb address in case we set linear addressing. */
246 	VBUF = vga_getgraphmem();
247 	MODETYPE = CONTEXT_LINEAR;
248 	if (modeinfo->maxpixels >= WIDTH * HEIGHT * 2)
249 	    MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
250 	if (modeinfo->maxpixels >= WIDTH * HEIGHT * 3)
251 	    MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
252 	switch (BYTESPERPIXEL) {
253 	case 1:
254 	    __currentcontext.ff = ff8;
255 	    break;
256 	case 2:
257 	    __currentcontext.ff = ff16;
258 	    break;
259 	case 3:
260 	    __currentcontext.ff = ff24;
261 	    break;
262 	case 4:
263 	    __currentcontext.ff = ff32;
264 	    break;
265 	}
266 	if (modeinfo->flags & RGB_MISORDERED)
267 	    MODEFLAGS |= MODEFLAG_32BPP_SHIFT8;
268     } else {
269 	/* Banked mode. */
270 	MODETYPE = CONTEXT_PAGED;
271 	if (modeinfo->maxpixels >= WIDTH * HEIGHT * 2)
272 	    MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
273 	if (modeinfo->maxpixels >= WIDTH * HEIGHT * 3)
274 	    MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
275 	if ((modeinfo->startaddressrange & 0x1ffff) == 0x10000) {
276 	    /* This hack is required for 320x200x256 page flipping */
277 	    /* on Trident, which doesn't work with bank boundary */
278 	    /* within the second page. */
279 	    MODEFLAGS |= MODEFLAG_FLIPPAGE_BANKALIGNED;
280 	}
281 	switch (BYTESPERPIXEL) {
282 	case 1:
283 	    __currentcontext.ff = ff8paged;
284 	    break;
285 	case 2:
286 	    __currentcontext.ff = ff16paged;
287 	    break;
288 	case 3:
289 	    __currentcontext.ff = ff24paged;
290 	    break;
291 	case 4:
292 	    __currentcontext.ff = ff32paged;
293 	    break;
294 	}
295 	if (modeinfo->flags & RGB_MISORDERED)
296 	    MODEFLAGS |= MODEFLAG_32BPP_SHIFT8;
297     }
298     if (vga_getcurrentmode() == m) {
299 	accelfuncs = vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_ACCEL);
300 	__svgalib_nonaccel_fillbox = __currentcontext.ff.driver_fillbox_func;
301 	if (accelfuncs & ACCELFLAG_FILLBOX)
302 	    __currentcontext.ff.driver_fillbox_func =
303 		__svgalib_driver8a_fillbox;
304 	if (accelfuncs & ACCELFLAG_SCREENCOPY)
305 	    __currentcontext.ff.driver_copybox_func =
306 		__svgalib_driver8a_copybox;
307     }
308 #ifdef DLL_CONTEXT_SHADOW
309     currentcontext = __currentcontext;
310 #endif
311     return 0;
312 }
313 
gl_setcontextvgavirtual(int m)314 int gl_setcontextvgavirtual(int m)
315 {
316     vga_modeinfo *modeinfo;
317     if (!vga_hasmode(m))
318 	return -1;
319     modeinfo = vga_getmodeinfo(m);
320     /* Set graphics context */
321     WIDTH = modeinfo->width;
322     HEIGHT = modeinfo->height;
323     if (modeinfo->flags & IS_MODEX) {
324 	/* Use a regular virtual screen for planar 256 color modes. */
325 	BYTESPERPIXEL = 1;
326 	BYTEWIDTH = modeinfo->linewidth * 4;
327     } else if (modeinfo->colors == 16) {
328 	/* Use a regular one byte per pixel virtual screen for */
329 	/* planar 16 color modes. */
330 	BYTESPERPIXEL = 1;
331 	BYTEWIDTH = modeinfo->linewidth * 8;
332     } else {
333 	BYTESPERPIXEL = modeinfo->bytesperpixel;
334 	BYTEWIDTH = modeinfo->linewidth;
335     }
336     COLORS = modeinfo->colors;
337     BITSPERPIXEL = colorbits(COLORS);
338     VBUF = malloc(SCREENSIZE(__currentcontext));
339     MODETYPE = CONTEXT_VIRTUAL;
340     MODEFLAGS = 0;
341     __clip = 0;
342     switch (BYTESPERPIXEL) {
343     case 1:
344 	__currentcontext.ff = ff8;
345 	break;
346     case 2:
347 	__currentcontext.ff = ff16;
348 	break;
349     case 3:
350 	__currentcontext.ff = ff24;
351 	break;
352     case 4:
353 	__currentcontext.ff = ff32;
354 	break;
355     }
356 #ifdef DLL_CONTEXT_SHADOW
357     currentcontext = __currentcontext;
358 #endif
359     return 0;
360 }
361 
gl_setcontextvirtual(int w,int h,int bpp,int bitspp,void * v)362 void gl_setcontextvirtual(int w, int h, int bpp, int bitspp, void *v)
363 {
364     WIDTH = w;
365     HEIGHT = h;
366     BYTESPERPIXEL = bpp;
367     BITSPERPIXEL = bitspp;
368     COLORS = 1 << bitspp;
369     BYTEWIDTH = WIDTH * BYTESPERPIXEL;
370     VBUF = v;
371     MODETYPE = CONTEXT_VIRTUAL;
372     MODEFLAGS = 0;
373     switch (BYTESPERPIXEL) {
374     case 1:
375 	__currentcontext.ff = ff8;
376 	break;
377     case 2:
378 	__currentcontext.ff = ff16;
379 	break;
380     case 3:
381 	__currentcontext.ff = ff24;
382 	break;
383     case 4:
384 	__currentcontext.ff = ff32;
385 	break;
386     }
387     __clip = 0;
388 #ifdef DLL_CONTEXT_SHADOW
389     currentcontext = __currentcontext;
390 #endif
391 }
392 
393 GraphicsContext *
gl_allocatecontext()394  gl_allocatecontext()
395 {
396     return malloc(sizeof(GraphicsContext));
397 }
398 
gl_setcontext(GraphicsContext * gc)399 void gl_setcontext(GraphicsContext * gc)
400 {
401     __currentcontext = *gc;
402 #ifdef DLL_CONTEXT_SHADOW
403     currentcontext = *gc;
404 #endif
405 }
406 
gl_getcontext(GraphicsContext * gc)407 void gl_getcontext(GraphicsContext * gc)
408 {
409     *gc = __currentcontext;
410 }
411 
gl_freecontext(GraphicsContext * gc)412 void gl_freecontext(GraphicsContext * gc)
413 {
414     if (gc->modetype == CONTEXT_VIRTUAL)
415 	free(gc->vbuf);
416 }
417 
gl_setcontextwidth(int w)418 void gl_setcontextwidth(int w)
419 {
420     __currentcontext.width = currentcontext.width = w;
421     __currentcontext.bytewidth = currentcontext.bytewidth =
422 	w * BYTESPERPIXEL;
423 }
424 
gl_setcontextheight(int h)425 void gl_setcontextheight(int h)
426 {
427     __currentcontext.height = currentcontext.height = h;
428 }
429 
430 
431 /* Clipping */
432 
gl_setclippingwindow(int x1,int y1,int x2,int y2)433 void gl_setclippingwindow(int x1, int y1, int x2, int y2)
434 {
435     __clip = 1;
436     __clipx1 = x1;
437     __clipy1 = y1;
438     __clipx2 = x2;
439     __clipy2 = y2;
440 }
441 
gl_enableclipping()442 void gl_enableclipping()
443 {
444     __clip = 1;
445     __clipx1 = 0;
446     __clipy1 = 0;
447     __clipx2 = WIDTH - 1;
448     __clipy2 = HEIGHT - 1;
449 }
450 
gl_disableclipping()451 void gl_disableclipping()
452 {
453     __clip = 0;
454 }
455 
456 
457 /* Primitive functions */
458 
gl_setpixel(int x,int y,int c)459 void gl_setpixel(int x, int y, int c)
460 {
461     if (__clip && outside(x, y))
462 	return;
463     setpixel(x, y, c);
464 }
465 
gl_getpixel(int x,int y)466 int gl_getpixel(int x, int y)
467 {
468     if (__clip && outside(x, y))
469 	return -1;
470     return getpixel(x, y);
471 }
472 
gl_hline(int x1,int y,int x2,int c)473 void gl_hline(int x1, int y, int x2, int c)
474 {
475     if (__clip) {
476 	if (y_outside(y))
477 	    return;
478 	clipxleft(x1);
479 	clipxright(x2);
480     }
481     if (x1 > x2)
482 	return;
483     hline(x1, y, x2, c);
484 }
485 
486 #define ADJUSTBITMAPBOX() \
487 	nw = w; nh = h; nx = x; ny = y;				\
488 	if (nx + nw < __clipx1 || nx > __clipx2)		\
489 		return;						\
490 	if (ny + nh < __clipy1 || ny > __clipy2)		\
491 		return;						\
492 	if (nx < __clipx1) {		/* left adjust */	\
493 		nw += nx - __clipx1;				\
494 		nx = __clipx1;					\
495 	}							\
496 	if (ny < __clipy1) {		/* top adjust */	\
497 		nh += ny - __clipy1;				\
498 		ny = __clipy1;					\
499 	}							\
500 	if (nx + nw > __clipx2)		/* right adjust */	\
501 		nw = __clipx2 - nx + 1;				\
502 	if (ny + nh > __clipy2)		/* bottom adjust */	\
503 		nh = __clipy2 - ny + 1;				\
504 
gl_fillbox(int x,int y,int w,int h,int c)505 void gl_fillbox(int x, int y, int w, int h, int c)
506 {
507     if (__clip) {
508 	if (x + w < __clipx1 || x > __clipx2)
509 	    return;
510 	if (y + h < __clipy1 || y > __clipy2)
511 	    return;
512 	if (x < __clipx1) {
513 	    w -= __clipx1 - x;
514 	    x = __clipx1;
515 	}
516 	if (y < __clipy1) {
517 	    h -= __clipy1 - y;
518 	    y = __clipy1;
519 	}
520 	if (x + w > __clipx2 + 1)
521 	    w = __clipx2 - x + 1;
522 	if (y + h > __clipy2 + 1)
523 	    h = __clipy2 - y + 1;
524     }
525     if (w <= 0 || h <= 0)
526 	return;
527     fillbox(x, y, w, h, c);
528 }
529 
gl_putboxpart(int x,int y,int w,int h,int ow,int oh,void * b,int ox,int oy)530 void gl_putboxpart(int x, int y, int w, int h, int ow, int oh, void *b,
531 		   int ox, int oy)
532 {
533     putboxpart(x, y, w, h, ow, oh, b, ox, oy);
534 }
535 
gl_putbox(int x,int y,int w,int h,void * b)536 void gl_putbox(int x, int y, int w, int h, void *b)
537 {
538     uchar *bp = b;
539     if (w <= 0 || h <= 0)
540 	return;
541     if (__clip) {
542 	int nx, ny, nw, nh;
543 	ADJUSTBITMAPBOX();
544 	if (nw <= 0 || nh <= 0)
545 	    return;
546 	if (nw != w || nh != h) {
547 	    putboxpart(nx, ny, nw, nh, w, h, bp, nx - x, ny - y);
548 	    return;
549 	}
550     }
551     putbox(x, y, w, h, bp, w);
552 }
553 
emulate_putboxmask(int x,int y,int w,int h,void * b)554 static void emulate_putboxmask(int x, int y, int w, int h, void *b)
555 {
556     void *box;
557     GraphicsContext gc;
558     box = alloca(w * h * BYTESPERPIXEL);
559     gl_getbox(x, y, w, h, box);	/* does clipping */
560 
561     gl_getcontext(&gc);		/* save context */
562 
563     /* create context that is only the box */
564     gl_setcontextvirtual(w, h, BYTESPERPIXEL, BITSPERPIXEL, box);
565     gl_putboxmask(0, 0, w, h, b);
566 
567     gl_setcontext(&gc);		/* restore context */
568     gl_putbox(x, y, w, h, box);
569 }
570 
gl_putboxmask(int x,int y,int w,int h,void * b)571 void gl_putboxmask(int x, int y, int w, int h, void *b)
572 {
573     if (w <= 0 || h <= 0)
574 	return;
575     if (__clip) {
576 	if (x + w < __clipx1 || x > __clipx2)
577 	    return;
578 	if (y + h < __clipy1 || y > __clipy2)
579 	    return;
580 	if (x < __clipx1 || y < __clipy1
581 	    || x + w > __clipx2 + 1 || y + h > __clipy2 + 1) {
582 	    /* clipping is not directly implemented */
583 	    emulate_putboxmask(x, y, w, h, b);
584 	    return;
585 	}
586     }
587     if (MODETYPE == CONTEXT_PAGED)
588 	/* paged primitive is not implemented */
589 	emulate_putboxmask(x, y, w, h, b);
590     else
591 	putboxmask(x, y, w, h, b);
592 }
593 
gl_getbox(int x,int y,int w,int h,void * b)594 void gl_getbox(int x, int y, int w, int h, void *b)
595 {
596     if (__clip) {
597 	int nx, ny, nw, nh;
598 	ADJUSTBITMAPBOX();
599 	if (nw <= 0 || nh <= 0)
600 	    return;
601 	if (nw != w || nh != h) {
602 	    getboxpart(nx, ny, nw, nh, w, h, b, nx - x, ny - y);
603 	    return;
604 	}
605     }
606     getbox(x, y, w, h, b, w);
607 }
608 
gl_copybox(int x1,int y1,int w,int h,int x2,int y2)609 void gl_copybox(int x1, int y1, int w, int h, int x2, int y2)
610 {
611 /* Doesn't handle clipping. */
612     if (MODETYPE == CONTEXT_PAGED) {
613 	/* Paged primitive is not implemented. */
614 	void *box;
615 	box = alloca(w * h * BYTESPERPIXEL);
616 	getbox(x1, y1, w, h, box, w);
617 	putbox(x2, y2, w, h, box, w);
618 	return;
619     }
620     copybox(x1, y1, w, h, x2, y2);
621 }
622 
623 
624 /* Miscellaneous functions */
625 
gl_clearscreen(int c)626 void gl_clearscreen(int c)
627 {
628     gl_fillbox(0, 0, WIDTH, HEIGHT, c);
629 }
630 
gl_rgbcolor(int r,int g,int b)631 int gl_rgbcolor(int r, int g, int b)
632 {
633     unsigned v;
634     switch (BITSPERPIXEL) {
635     case 8:
636 	/* assumes RGB palette at index 0-255 */
637 	/* bits 0-2 = blue (3 bits) */
638 	/*      3-5 = green (3 bits) */
639 	/*      6-7 = red (2 bits) */
640 	return (r & 0xc0) + ((g & 0xe0) >> 2) + (b >> 5);
641     case 24:
642     case 32:
643 	v = (r << 16) + (g << 8) + b;
644 	if (MODEFLAGS & MODEFLAG_32BPP_SHIFT8)
645 	    return v << 8;
646 	return v;
647     case 15:
648 	return ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + (b >> 3);
649     case 16:
650 	return ((r & 0xf8) << 8) + ((g & 0xfc) << 3) + (b >> 3);
651     case 4:
652 	/* Now this is real fun. Map to standard EGA palette. */
653 	v = 0;
654 	if (b >= 64)
655 	    v += 1;
656 	if (g >= 64)
657 	    v += 2;
658 	if (r >= 64)
659 	    v += 4;
660 	if (b >= 192 || g >= 192 || r >= 192)
661 	    v += 8;
662 	return v;
663     }
664     return -1;
665 }
666 
gl_setpixelrgb(int x,int y,int r,int g,int b)667 void gl_setpixelrgb(int x, int y, int r, int g, int b)
668 {
669 /* Color components range from 0 to 255 */
670     if (__clip && outside(x, y))
671 	return;
672     setpixel(x, y, gl_rgbcolor(r, g, b));
673 }
674 
gl_getpixelrgb(int x,int y,int * r,int * g,int * b)675 void gl_getpixelrgb(int x, int y, int *r, int *g, int *b)
676 {
677     unsigned c;
678     if (__clip && outside(x, y)) {
679 	*r = *g = *b = -1;
680 	return;
681     }
682     c = getpixel(x, y);
683     switch (BITSPERPIXEL) {
684     case 8:
685 	*b = (c & (1 + 2 + 4)) << 5;	/* bits 0-2 */
686 	*g = (c & (8 + 16 + 32)) << 2;	/* bits 3-5 */
687 	*r = (c & (64 + 128));	/* bits 6-7 */
688 	break;
689     case 32:
690 	if (MODEFLAGS & MODEFLAG_32BPP_SHIFT8) {
691 	    *b = (c & 0xff00) >> 8;
692 	    *g = (c & 0xff0000) >> 16;
693 	    *r = c >> 24;
694 	    break;
695 	}
696     case 24:
697 	*b = c & 0xff;
698 	*g = (c & 0xff00) >> 8;
699 	*r = c >> 16;
700 	break;
701     case 15:
702 	*b = (c & (1 + 2 + 4 + 8 + 16)) << 3;
703 	*g = (c & (32 + 64 + 128 + 256 + 512)) >> 2;
704 	*r = (c & (1024 + 2048 + 4096 + 8192 + 16384)) >> 7;
705 	break;
706     case 16:
707 	*b = (c & (1 + 2 + 4 + 8 + 16)) << 3;
708 	*g = (c & (32 + 64 + 128 + 256 + 512 + 1024)) >> 3;
709 	*r = (c & (2048 + 4096 + 8192 + 16384 + 32768)) >> 8;
710 	break;
711     case 4:
712 	*b = (c & 1) * ((c & 8) ? 255 : 128);
713 	*g = (c & 2) * ((c & 8) ? 255 : 128);
714 	*r = (c & 4) * ((c & 8) ? 255 : 128);
715 	break;
716     }
717 }
718 
gl_setdisplaystart(int x,int y)719 void gl_setdisplaystart(int x, int y)
720 {
721     vga_setdisplaystart(y * BYTEWIDTH + x * BYTESPERPIXEL);
722 }
723 
724 
725 /* Screen copying */
726 
gl_setscreenoffset(int o)727 void gl_setscreenoffset(int o)
728 {
729     screenoffset = o;
730 }
731 
gl_enablepageflipping(GraphicsContext * gc)732 int gl_enablepageflipping(GraphicsContext * gc)
733 {
734     if (gc->modeflags & MODEFLAG_PAGEFLIPPING_CAPABLE) {
735 	gc->modeflags |= MODEFLAG_PAGEFLIPPING_ENABLED;
736     }
737     if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_CAPABLE) {
738 	gc->modeflags &= ~(MODEFLAG_PAGEFLIPPING_ENABLED);
739 	gc->modeflags |= MODEFLAG_TRIPLEBUFFERING_ENABLED;
740     }
741     gc->flippage = 0;
742     if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_ENABLED)
743 	return 3;
744     if (gc->modeflags & MODEFLAG_PAGEFLIPPING_ENABLED)
745 	return 2;
746     return 0;
747 }
748 
gl_copyscreen(GraphicsContext * gc)749 void gl_copyscreen(GraphicsContext * gc)
750 {
751     int size;
752     void *svp, *dvp;
753 
754     if (gc->modeflags & MODEFLAG_PAGEFLIPPING_ENABLED)
755 	gc->flippage ^= 1;
756     if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_ENABLED)
757 	gc->flippage = (gc->flippage + 1) % 3;
758     if (gc->modeflags & (MODEFLAG_PAGEFLIPPING_ENABLED |
759 			 MODEFLAG_TRIPLEBUFFERING_ENABLED)) {
760 	/* Calculate screen offset in bytes. */
761 	screenoffset = gc->bytewidth * HEIGHT * gc->flippage;
762 	if (gc->modeflags & MODEFLAG_FLIPPAGE_BANKALIGNED)
763 	    screenoffset = ((screenoffset + 0xffff) & ~0xffff);
764     }
765     if (gc->modetype == CONTEXT_MODEX) {
766 	vga_copytoplanar256(VBUF, BYTEWIDTH, screenoffset / 4,
767 			    gc->bytewidth / 4, WIDTH, HEIGHT);
768 	goto end;
769     }
770     if (gc->modetype == CONTEXT_PLANAR16) {
771 	if (WIDTH == 1024 && HEIGHT >= 512 &&
772 	    ((screenoffset / 8) & 0xffff) == 0) {
773 	    /* Kludge to allow 1024x768x16 with page flipping. */
774 	    int page;
775 	    page = (screenoffset / 8) >> 16;
776 	    vga_setpage(page);
777 	    vga_copytoplanar16(VBUF, BYTEWIDTH, 0,
778 			       gc->bytewidth / 8, WIDTH, 512);
779 	    vga_setpage(page + 1);
780 	    vga_copytoplanar16(VBUF + WIDTH * 512, BYTEWIDTH,
781 			       0, gc->bytewidth / 8, WIDTH, HEIGHT - 512);
782 	    return;
783 	}
784 	if (WIDTH * HEIGHT >= 512 * 1024)
785 	    /* We don't handle banking. */
786 	    return;
787 
788 	vga_copytoplanar16(VBUF, BYTEWIDTH, screenoffset / 8,
789 			   gc->bytewidth / 8, WIDTH, HEIGHT);
790 	goto end;
791     }
792     if (BYTESPERPIXEL == 4 && gc->bytesperpixel == 3) {
793 	/* Special case. */
794 	int soffset, doffset;
795 	if (BYTEWIDTH / 4 != gc->bytewidth / 3) {
796 	    /* Even more special case for physical truecolor */
797 	    /* modes that have extra scanline padding. */
798 	    /* This has the effect of slowing down */
799 	    /* '3d' in some truecolor modes on ATI mach32. */
800 	    gl_copyboxtocontext(0, 0, WIDTH, HEIGHT, gc, 0, 0);
801 	    goto end;
802 	}
803 	soffset = 0;
804 	doffset = screenoffset;
805 	size = WIDTH * HEIGHT;
806 	while (soffset / 4 < size) {
807 	    int schunk, dchunk;
808 	    int count;
809 	    schunk = __svgalib_driver_setread(&__currentcontext, soffset, &svp);
810 	    dchunk = __svgalib_driver_setwrite(gc, doffset, &dvp);
811 	    if (dchunk == 1) {
812 		/* One byte left in segment. */
813 		int pix;
814 		pix = *(unsigned *) svp;	/* 32-bit pixel */
815 		*(unsigned char *) dvp = pix;
816 		dchunk = __svgalib_driver_setwrite(gc, doffset + 1, &dvp);
817 		*(unsigned short *) dvp = pix >> 8;
818 		count = 1;	/* 1 pixel handled. */
819 	    } else if (dchunk == 2) {
820 		/* Two bytes left. */
821 		int pix;
822 		pix = *(unsigned *) svp;	/* 32-bit pixel */
823 		*(unsigned short *) dvp = pix;
824 		dchunk = __svgalib_driver_setwrite(gc, doffset + 2, &dvp);
825 		*(unsigned char *) dvp = pix >> 16;
826 		count = 1;	/* 1 pixel handled. */
827 	    } else {
828 		count = min(min(schunk / 4, dchunk / 3),
829 			    size - (soffset / 4));
830 		__svgalib_memcpy4to3(dvp, svp, count);
831 	    }
832 	    soffset += count * 4;
833 	    doffset += count * 3;
834 	}
835 	goto end;
836     }
837     if (BYTESPERPIXEL == 4 && gc->bytesperpixel == 4 &&
838 	(gc->modeflags & MODEFLAG_32BPP_SHIFT8)) {
839 	int soffset = 0;
840 	int doffset = screenoffset;
841 	size = SCREENSIZE(__currentcontext);
842 	while (soffset < size) {
843 	    int schunk, dchunk;
844 	    int count;
845 	    schunk = __svgalib_driver_setread(&__currentcontext, soffset, &svp);
846 	    dchunk = __svgalib_driver_setwrite(gc, doffset, &dvp);
847 	    count = min(min(schunk, dchunk), (size - soffset));
848 	    __svgalib_memcpy32shift8(dvp, svp, count / 4);
849 	    soffset += count;
850 	    doffset += count;
851 	}
852     } else {
853 	int soffset = 0;
854 	int doffset = screenoffset;
855 	size = SCREENSIZE(__currentcontext);
856 	while (soffset < size) {
857 	    int schunk, dchunk;
858 	    int count;
859 	    schunk = __svgalib_driver_setread(&__currentcontext, soffset, &svp);
860 	    dchunk = __svgalib_driver_setwrite(gc, doffset, &dvp);
861 	    count = min(min(schunk, dchunk), (size - soffset));
862 	    __memcpy(dvp, svp, count);
863 	    soffset += count;
864 	    doffset += count;
865 	}
866     }
867 
868   end:
869     if (gc->modeflags & (MODEFLAG_PAGEFLIPPING_ENABLED |
870 			 MODEFLAG_TRIPLEBUFFERING_ENABLED)) {
871 	GraphicsContext save;
872 	/* setdisplaystart will use BYTEWIDTH of the virtual screen, */
873 	/* which is what we want since vga_setdisplaystart is */
874 	/* defined in terms of pixel offset (except for hicolor */
875 	/* modes, which are defined in terms of bytes). */
876 	gl_getcontext(&save);
877 	gl_setcontext(gc);
878 	if (gc->modeflags & MODEFLAG_FLIPPAGE_BANKALIGNED)
879 	    vga_setdisplaystart(screenoffset);
880 	else
881 	    gl_setdisplaystart(0, gc->height * gc->flippage);
882 	gl_setcontext(&save);
883 	/* For page flipping, it might be appropriate to add a */
884 	/* waitverticalretrace here. */
885     }
886     screenoffset = 0;
887 }
888 
gl_copyboxtocontext(int x1,int y1,int w,int h,GraphicsContext * gc,int x2,int y2)889 void gl_copyboxtocontext(int x1, int y1, int w, int h, GraphicsContext * gc,
890 			 int x2, int y2)
891 {
892 /* This is now reasonably efficient if clipping is not enabled. */
893     void *buf;
894     GraphicsContext save;
895     gl_getcontext(&save);
896     if ((MODETYPE == CONTEXT_LINEAR || MODETYPE == CONTEXT_VIRTUAL) &&
897 	(BYTESPERPIXEL == gc->bytesperpixel) &&
898 	!__clip && !gc->clip) {
899 #ifdef DLL_CONTEXT_SHADOW
900 	__currentcontext = *gc;
901 #else
902 	gl_setcontext(gc);
903 #endif
904 /*
905  * Note: Using save.bytewidth / BYTESPERPIXEL is probably not an optimal hack here.
906  * it would be better to transfer save.bytewidth to putbox as it is what is really
907  * used there. However, putbox is used all over interpreting the last entry as a
908  * pixel count, so we keep it this way to avoid problems if some other place not
909  * updated by accident.
910  */
911 	putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, save.vbuf +
912 	       y1 * save.bytewidth + x1 * BYTESPERPIXEL,
913 	       save.bytewidth / BYTESPERPIXEL);
914 	goto end;
915     }
916     buf = alloca(w * h * BYTESPERPIXEL);
917     gl_getbox(x1, y1, w, h, buf);
918 #ifdef DLL_CONTEXT_SHADOW
919     __currentcontext = *gc;
920 #else
921     gl_setcontext(gc);
922 #endif
923 
924     if (save.bytesperpixel == 4 && gc->bytesperpixel == 3) {
925 	/* Special case conversion from 32-bit virtual screen to */
926 	/* 24-bit truecolor framebuffer. */
927 	if (gc->modetype == CONTEXT_PAGED || gc->clip) {
928 	    /* For paged modes or clipping, use another buffer. */
929 	    void *buf2;
930 	    buf2 = alloca(w * h * 3);
931 	    __svgalib_memcpy4to3(buf2, buf, w * h);
932 	    gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h,
933 		      buf2);
934 	} else
935 	    /* No clipping, linear. */
936 	    __svgalib_driver24_putbox32(x2, y2, w, h, buf, w);
937     } else			/* Contexts assumed to have same pixel size. */
938 	gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, buf);
939 
940   end:
941 #ifdef DLL_CONTEXT_SHADOW
942     __currentcontext = save;
943 #else
944     gl_setcontext(&save);
945 #endif
946 }
947 
gl_copyboxfromcontext(GraphicsContext * gc,int x1,int y1,int w,int h,int x2,int y2)948 void gl_copyboxfromcontext(GraphicsContext * gc, int x1, int y1, int w, int h,
949 			   int x2, int y2)
950 {
951     void *buf;
952     GraphicsContext save;
953     if ((gc->modetype == CONTEXT_LINEAR || gc->modetype == CONTEXT_VIRTUAL) &&
954 	(BYTESPERPIXEL == gc->bytesperpixel) &&
955 	!__clip && !gc->clip) {
956 /*
957  * see above on  gc->bytewidth / BYTESPERPIXEL.
958  */
959 	putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, gc->vbuf +
960 	       y1 * gc->bytewidth + x1 * BYTESPERPIXEL,
961 	       gc->bytewidth / BYTESPERPIXEL);
962 	return;
963     }
964     gl_getcontext(&save);
965 #ifdef DLL_CONTEXT_SHADOW
966     __currentcontext = *gc;
967 #else
968     gl_setcontext(gc);
969 #endif
970     buf = alloca(w * h * BYTESPERPIXEL);
971     gl_getbox(x1, y1, w, h, buf);
972 #ifdef DLL_CONTEXT_SHADOW
973     __currentcontext = save;
974 #else
975     gl_setcontext(&save);
976 #endif
977 
978     if (gc->bytesperpixel == 4 && save.bytesperpixel == 3) {
979 	/* Special case conversion from 32-bit virtual screen to */
980 	/* 24-bit truecolor framebuffer. */
981 	if (save.modetype == CONTEXT_PAGED || save.clip) {
982 	    /* For paged modes or clipping, use another buffer. */
983 	    void *buf2;
984 	    buf2 = alloca(w * h * 3);
985 	    __svgalib_memcpy4to3(buf2, buf, w * h);
986 	    gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h,
987 		      buf2);
988 	} else
989 	    /* No clipping, linear. */
990 	    __svgalib_driver24_putbox32(x2, y2, w, h, buf, w);
991     } else			/* Contexts assumed to have same pixel size. */
992 	gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, buf);
993 }
994