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