home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / SVGALIB / SVGALIB1.TAR / svgalib / gl / grlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  22.3 KB  |  909 lines

  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.  
  15. /* Global variables */
  16.  
  17. #ifdef DLL_CONTEXT_SHADOW
  18.  
  19. /* The current context variable is shadowed in a read-only variable for */
  20. /* external use. */
  21.  
  22. GraphicsContext __currentcontext;    /* Internal current context. */
  23. GraphicsContext currentcontext;        /* Copy for external use. */
  24.  
  25. #else
  26.  
  27. GraphicsContext currentcontext;
  28.  
  29. #endif
  30.  
  31. static int screenoffset = 0;    /* Used by copy(box)toscreen. */
  32.  
  33.  
  34. /* Framebuffer function pointers */
  35.  
  36. static framebufferfunctions ff8 = {
  37.     driver8_setpixel,
  38.     driver8_getpixel,
  39.     driver8_hline,
  40.     driver8_fillbox,
  41.     driver8_putbox,
  42.     driver8_getbox,
  43.     driver8_putboxmask,
  44.     driver8_putboxpart,
  45.     driver8_getboxpart,
  46.     driver8_copybox
  47. };
  48.  
  49. static framebufferfunctions ff16 = {
  50.     driver16_setpixel,
  51.     driver16_getpixel,
  52.     driver16_hline,
  53.     driver16_fillbox,
  54.     driver16_putbox,
  55.     driver16_getbox,
  56.     driver16_putboxmask,
  57.     driver16_putboxpart,
  58.     driver16_getboxpart,
  59.     driver16_copybox
  60. };
  61.  
  62. static framebufferfunctions ff24 = {
  63.     driver24_setpixel,
  64.     driver24_getpixel,
  65.     driver24_hline,
  66.     driver24_fillbox,
  67.     driver24_putbox,
  68.     driver24_getbox,
  69.     driver24_putboxmask,
  70.     driver24_putboxpart,
  71.     driver24_getboxpart,
  72.     driver24_copybox
  73. };
  74.  
  75. static framebufferfunctions ff32 = {
  76.     driver32_setpixel,
  77.     driver32_getpixel,
  78.     driver32_hline,
  79.     driver32_fillbox,
  80.     driver32_putbox,
  81.     driver32_getbox,
  82.     driver32_putboxmask,
  83.     driver32_putboxpart,
  84.     driver32_getboxpart,
  85.     driver32_copybox
  86. };
  87.  
  88. static framebufferfunctions ff8paged = {
  89.     driver8p_setpixel,
  90.     driver8p_getpixel,
  91.     driver8p_hline,
  92.     driver8p_fillbox,
  93.     driver8p_putbox,
  94.     driver8p_getbox,
  95.     driver8p_putboxmask,
  96.     driver8p_putboxpart,
  97.     driver8p_getboxpart,
  98.     driver8p_copybox
  99. };
  100.  
  101. static framebufferfunctions ff16paged = {
  102.     driver16p_setpixel,
  103.     driver16p_getpixel,
  104.     driver16p_hline,
  105.     driver16p_fillbox,
  106.     driver16p_putbox,
  107.     driver16p_getbox,
  108.     driver16p_putboxmask,
  109.     driver16p_putboxpart,
  110.     driver16p_getboxpart,
  111.     driver16p_copybox
  112. };
  113.  
  114. static framebufferfunctions ff24paged = {
  115.     driver24p_setpixel,
  116.     driver24p_getpixel,
  117.     driver24p_hline,
  118.     driver24p_fillbox,
  119.     driver24p_putbox,
  120.     driver24p_getbox,
  121.     driver24p_putboxmask,
  122.     driver24p_putboxpart,
  123.     driver24p_getboxpart,
  124.     driver24p_copybox
  125. };
  126.  
  127. static framebufferfunctions ff32paged = {
  128.     driver32p_setpixel,
  129.     driver32p_getpixel,
  130.     driver32p_hline,
  131.     driver32p_fillbox,
  132.     driver32p_putbox,
  133.     driver32p_getbox,
  134.     driver32p_putboxmask,
  135.     driver32p_putboxpart,
  136.     driver32p_getboxpart,
  137.     driver32p_copybox
  138. };
  139.  
  140. static framebufferfunctions ffplanar256 = {
  141.     driverplanar256_nothing,
  142.     driverplanar256_nothing,
  143.     driverplanar256_nothing,
  144.     driverplanar256_nothing,
  145.     driverplanar256_putbox,
  146.     driverplanar256_nothing,
  147.     driverplanar256_nothing,
  148.     driverplanar256_nothing,
  149.     driverplanar256_nothing,
  150.     driverplanar256_nothing,
  151. };
  152.  
  153. static framebufferfunctions ffplanar16 = {
  154.     driverplanar16_nothing,
  155.     driverplanar16_nothing,
  156.     driverplanar16_nothing,
  157.     driverplanar16_nothing,
  158.     driverplanar16_nothing,
  159.     driverplanar16_nothing,
  160.     driverplanar16_nothing,
  161.     driverplanar16_nothing,
  162.     driverplanar16_nothing,
  163.     driverplanar16_nothing,
  164. };
  165.  
  166.  
  167. /* Initialization and graphics contexts */
  168.  
  169. #define SCREENSIZE(gc) ((gc).bytewidth * (gc).height)
  170.  
  171. static int colorbits( int c ) {
  172.     switch (c) {
  173.     case 256 : return 8;
  174.     case 32768 : return 15;
  175.     case 65536 : return 16;
  176.     case 256 * 65536 : return 24;
  177.     }
  178. }
  179.  
  180. int gl_setcontextvga( int m ) {
  181.     framebufferfunctions *ff;
  182.     vga_modeinfo *modeinfo;
  183.     int accelfuncs;
  184.     if (!vga_hasmode(m))
  185.         return -1;
  186.     modeinfo = vga_getmodeinfo(m);
  187.     /* Set graphics context */
  188.     WIDTH = modeinfo->width;
  189.     HEIGHT = modeinfo->height;
  190.     BYTESPERPIXEL = modeinfo->bytesperpixel;
  191.     COLORS = modeinfo->colors;
  192.     BITSPERPIXEL = colorbits(COLORS);
  193.     BYTEWIDTH = modeinfo->linewidth;
  194.     VBUF = vga_getgraphmem();
  195.     MODEFLAGS = 0;
  196.     __clip = 0;
  197.     ff = &(__currentcontext.ff);
  198.     if (modeinfo->flags & IS_MODEX) {
  199.         /* Pretend it's a regular (linear) context. */
  200.         BYTESPERPIXEL = 1;
  201.         BYTEWIDTH *= 4;
  202.         MODETYPE = CONTEXT_MODEX;
  203.         if (BYTEWIDTH * HEIGHT * 2 <= 256 * 1024)
  204.             MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
  205.         if (BYTEWIDTH * HEIGHT * 3 <= 256 * 1024)
  206.             MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
  207.         __currentcontext.ff = ffplanar256;
  208.     }
  209.     else
  210.     if (modeinfo->colors == 16) {
  211.         /* Pretend it's a regular one byte per pixel context. */
  212.         BYTESPERPIXEL = 1;
  213.         BYTEWIDTH *= 8;
  214.         MODETYPE = CONTEXT_PLANAR16;
  215.         if (BYTEWIDTH * HEIGHT <= 256 * 1024)
  216.             MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
  217.         if (BYTEWIDTH * HEIGHT * 3 / 2 <= 256 * 1024)
  218.             MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
  219.     }
  220.     else
  221.     if ((m == G320x200x256 && modeinfo->maxpixels <= 65536) ||
  222.     (modeinfo->flags & IS_LINEAR)
  223. #if 0    /* svgalib doesn't VT-switch correctly with linear addressing. */
  224.     || ((modeinfo->flags & CAPABLE_LINEAR)
  225.     /* Creepy. Try linear addressing only if the mode is set. */
  226.     && vga_getcurrentmode() == m && (vga_setlinearaddressing() != -1))
  227. #endif
  228.     ) {
  229.         /* No banking.*/
  230.         /* Get get the fb address in case we set linear addressing. */
  231.         VBUF = vga_getgraphmem();
  232.         MODETYPE = CONTEXT_LINEAR;
  233.         if (modeinfo->maxpixels >= WIDTH * HEIGHT * 2)
  234.             MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
  235.         if (modeinfo->maxpixels >= WIDTH * HEIGHT * 3)
  236.             MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
  237.         switch (BYTESPERPIXEL) {
  238.             case 1 : __currentcontext.ff = ff8; break;
  239.             case 2 : __currentcontext.ff = ff16; break;
  240.             case 3 : __currentcontext.ff = ff24; break;
  241.             case 4 : __currentcontext.ff = ff32; break;
  242.         }
  243.         if (modeinfo->flags & RGB_MISORDERED)
  244.             MODEFLAGS |= MODEFLAG_32BPP_SHIFT8;
  245.     }
  246.     else {
  247.         /* Banked mode. */
  248.         MODETYPE = CONTEXT_PAGED;
  249.         if (modeinfo->maxpixels >= WIDTH * HEIGHT * 2)
  250.             MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
  251.         if (modeinfo->maxpixels >= WIDTH * HEIGHT * 3)
  252.             MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
  253.         if ((modeinfo->startaddressrange & 0x1ffff) == 0x10000) {
  254.             /* This hack is required for 320x200x256 page flipping */
  255.             /* on Trident, which doesn't work with bank boundary */
  256.             /* within the second page. */
  257.             MODEFLAGS |= MODEFLAG_FLIPPAGE_BANKALIGNED;
  258.         }
  259.         switch (BYTESPERPIXEL) {
  260.             case 1 : __currentcontext.ff = ff8paged; break;
  261.             case 2 : __currentcontext.ff = ff16paged; break;
  262.             case 3 : __currentcontext.ff = ff24paged; break;
  263.             case 4 : __currentcontext.ff = ff32paged; break;
  264.         }
  265.     }
  266.     if (vga_getcurrentmode() == m) {
  267.         accelfuncs = vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_ACCEL);
  268.         if (accelfuncs & ACCELFLAG_FILLBOX)
  269.             __currentcontext.ff.driver_fillbox_func =
  270.                 driver8a_fillbox;
  271.         if (accelfuncs & ACCELFLAG_SCREENCOPY)
  272.             __currentcontext.ff.driver_copybox_func =
  273.                 driver8a_copybox;
  274.     }
  275.     #ifdef DLL_CONTEXT_SHADOW
  276.     currentcontext = __currentcontext;
  277.     #endif
  278. }
  279.  
  280. int gl_setcontextvgavirtual( int m ) {
  281.     vga_modeinfo *modeinfo;
  282.     if (!vga_hasmode(m))
  283.         return -1;
  284.     modeinfo = vga_getmodeinfo(m);
  285.     /* Set graphics context */
  286.     WIDTH = modeinfo->width;
  287.     HEIGHT = modeinfo->height;
  288.     if (modeinfo->flags & IS_MODEX) {
  289.         /* Use a regular virtual screen for planar 256 color modes. */
  290.         BYTESPERPIXEL = 1;
  291.         BYTEWIDTH = modeinfo->linewidth * 4;
  292.     }
  293.     else
  294.     if (modeinfo->colors == 16) {
  295.         /* Use a regular one byte per pixel virtual screen for */
  296.         /* planar 16 color modes. */
  297.         BYTESPERPIXEL = 1;
  298.         BYTEWIDTH = modeinfo->linewidth * 8;
  299.     }
  300.     else {
  301.         BYTESPERPIXEL = modeinfo->bytesperpixel;
  302.         BYTEWIDTH = modeinfo->linewidth;
  303.     }
  304.     COLORS = modeinfo->colors;
  305.     BITSPERPIXEL = colorbits(COLORS);
  306.     VBUF = malloc(SCREENSIZE(__currentcontext));
  307.     MODETYPE = CONTEXT_VIRTUAL;
  308.     MODEFLAGS = 0;
  309.     __clip = 0;
  310.     switch (BYTESPERPIXEL) {
  311.         case 1 : __currentcontext.ff = ff8; break;
  312.         case 2 : __currentcontext.ff = ff16; break;
  313.         case 3 : __currentcontext.ff = ff24; break;
  314.         case 4 : __currentcontext.ff = ff32; break;
  315.     }
  316.     #ifdef DLL_CONTEXT_SHADOW
  317.     currentcontext = __currentcontext;
  318.     #endif
  319. }
  320.  
  321. void gl_setcontextvirtual( int w, int h, int bpp, int bitspp, void *v ) {
  322.     WIDTH = w;
  323.     HEIGHT = h;
  324.     BYTESPERPIXEL = bpp;
  325.     BITSPERPIXEL = bitspp;
  326.     COLORS = 1 << bitspp;
  327.     BYTEWIDTH = WIDTH * BYTESPERPIXEL;
  328.     VBUF = v;
  329.     MODETYPE = CONTEXT_VIRTUAL;
  330.     MODEFLAGS = 0;
  331.     switch (BYTESPERPIXEL) {
  332.         case 1 : __currentcontext.ff = ff8; break;
  333.         case 2 : __currentcontext.ff = ff16; break;
  334.         case 3 : __currentcontext.ff = ff24; break;
  335.         case 4 : __currentcontext.ff = ff32; break;
  336.     }
  337.     __clip = 0;
  338.     #ifdef DLL_CONTEXT_SHADOW
  339.     currentcontext = __currentcontext;
  340.     #endif
  341. }
  342.  
  343. GraphicsContext *gl_allocatecontext() {
  344.     return malloc(sizeof(GraphicsContext));
  345. }
  346.  
  347. void gl_setcontext( GraphicsContext *gc ) {
  348.     __currentcontext = *gc;
  349.     #ifdef DLL_CONTEXT_SHADOW
  350.     currentcontext = *gc;
  351.     #endif
  352. }
  353.  
  354. void gl_getcontext( GraphicsContext *gc ) {
  355.     *gc = __currentcontext;
  356. }
  357.  
  358. void gl_freecontext( GraphicsContext *gc ) {
  359.     if (gc->modetype == CONTEXT_VIRTUAL)
  360.         free(gc->vbuf);
  361. }
  362.  
  363. void gl_setcontextwidth(w) {
  364.     __currentcontext.width = currentcontext.width = w;
  365.     __currentcontext.bytewidth = currentcontext.bytewidth =
  366.         w * BYTESPERPIXEL;
  367. }
  368.  
  369. void gl_setcontextheight(h) {
  370.     __currentcontext.height = currentcontext.height = h;
  371. }
  372.  
  373.  
  374. /* Clipping */
  375.  
  376. void gl_setclippingwindow( int x1, int y1, int x2, int y2 ) {
  377.     __clip = 1;
  378.     __clipx1 = x1;
  379.     __clipy1 = y1;
  380.     __clipx2 = x2;
  381.     __clipy2 = y2;
  382. }
  383.  
  384. void gl_enableclipping() {
  385.     __clip = 1;
  386.     __clipx1 = 0;
  387.     __clipy1 = 0;
  388.     __clipx2 = WIDTH - 1;
  389.     __clipy2 = HEIGHT - 1;
  390. }
  391.  
  392. void gl_disableclipping() {
  393.     __clip = 0;
  394. }
  395.  
  396.  
  397. /* Primitive functions */
  398.  
  399. void gl_setpixel( int x, int y, int c ) {
  400.     if (__clip && outside(x, y))
  401.         return;
  402.     setpixel(x, y, c);
  403. }
  404.  
  405. int gl_getpixel( int x, int y ) {
  406.     if (__clip && outside(x, y))
  407.         return -1;
  408.     return getpixel(x, y);
  409. }
  410.  
  411. void gl_hline( int x1, int y, int x2, int c ) {
  412.     if (__clip) {
  413.         if (y_outside(y))
  414.             return;
  415.         clipxleft(x1);
  416.         clipxright(x2);
  417.         if (x1 > x2)
  418.             return;
  419.     }
  420.     hline(x1, y, x2, c);
  421. }
  422.  
  423. #define ADJUSTBITMAPBOX() \
  424.     nw = w; nh = h; nx = x; ny = y;                \
  425.     if (nx + nw < __clipx1 || nx > __clipx2)        \
  426.         return;                        \
  427.     if (ny + nh < __clipy1 || ny > __clipy2)        \
  428.         return;                        \
  429.     if (nx < __clipx1) {        /* left adjust */    \
  430.         nw += nx - __clipx1;                \
  431.         nx = __clipx1;                    \
  432.     }                            \
  433.     if (ny < __clipy1) {        /* top adjust */    \
  434.         nh += ny - __clipy1;                \
  435.         ny = __clipy1;                    \
  436.     }                            \
  437.     if (nx + nw > __clipx2)        /* right adjust */    \
  438.         nw = __clipx2 - nx + 1;                \
  439.     if (ny + nh > __clipy2)        /* bottom adjust */    \
  440.         nh = __clipy2 - ny + 1;                \
  441.  
  442. void gl_fillbox( int x, int y, int w, int h, int c ) {
  443.     if (__clip) {
  444.         if (x + w < __clipx1 || x > __clipx2)        
  445.             return;                        
  446.         if (y + h < __clipy1 || y > __clipy2)        
  447.             return;
  448.         if (x < __clipx1) {
  449.             w -= __clipx1 - x;
  450.             x = __clipx1;
  451.         }
  452.         if (y < __clipy1) {
  453.             h -= __clipy1 - y;
  454.             y = __clipy1;
  455.         }
  456.         if (x + w > __clipx2 + 1)
  457.             w = __clipx2 - x + 1;
  458.         if (y + h > __clipy2 + 1)
  459.             h = __clipy2 - y + 1;
  460.     }
  461.     if (w <= 0 || h <= 0)
  462.         return;
  463.     fillbox(x, y, w, h, c);
  464. }
  465.  
  466. void gl_putboxpart( int x, int y, int w, int h, int ow, int oh, void *b,
  467. int ox, int oy ) {
  468.     putboxpart(x, y, w, h, ow, oh, b, ox, oy);
  469. }
  470.  
  471. void gl_putbox( int x, int y, int w, int h, void *b ) {
  472.     uchar *bp = b;
  473.     if (w <= 0 || h <= 0)
  474.         return;
  475.     if (__clip) {
  476.         int nx, ny, nw, nh;
  477.         ADJUSTBITMAPBOX();
  478.         if (nw <= 0 || nh <= 0)
  479.             return;
  480.         if (nw != w || nh != h) {
  481.             putboxpart(nx, ny, nw, nh, w, h, bp, nx - x, ny - y);
  482.             return;
  483.         }
  484.     }
  485.     putbox(x, y, w, h, bp, w);
  486. }
  487.  
  488. static void emulate_putboxmask( int x, int y, int w, int h, void *b ) {
  489.     void *box;
  490.     GraphicsContext gc;
  491.     box = alloca(w * h * BYTESPERPIXEL);
  492.     gl_getbox(x, y, w, h, box);    /* does clipping */
  493.  
  494.     gl_getcontext(&gc);        /* save context */
  495.  
  496.     /* create context that is only the box */
  497.     gl_setcontextvirtual(w, h, BYTESPERPIXEL, BITSPERPIXEL, box);
  498.     gl_putboxmask(0, 0, w, h, b);
  499.  
  500.     gl_setcontext(&gc);        /* restore context */
  501.     gl_putbox(x, y, w, h, box);
  502. }
  503.  
  504. void gl_putboxmask( int x, int y, int w, int h, void *b ) {
  505.     if (w <= 0 || h <= 0)
  506.         return;
  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 || y < __clipy1
  513.         || x + w > __clipx2 + 1 || y + h > __clipy2 + 1) {
  514.             /* clipping is not directly implemented */
  515.             emulate_putboxmask(x, y, w, h, b);
  516.             return;
  517.         }
  518.     }
  519.     if (MODETYPE == CONTEXT_PAGED)
  520.         /* paged primitive is not implemented */
  521.         emulate_putboxmask(x, y, w, h, b);
  522.     else
  523.         putboxmask(x, y, w, h, b);
  524. }
  525.  
  526. void gl_getbox( int x, int y, int w, int h, void *b ) {
  527.     if (__clip) {
  528.         int nx, ny, nw, nh;
  529.         ADJUSTBITMAPBOX();
  530.         if (nw <= 0 || nh <= 0)
  531.             return;
  532.         if (nw != w || nh != h) {
  533.             getboxpart(nx, ny, nw, nh, w, h, b, nx - x, ny - y);
  534.             return;
  535.         }
  536.     }
  537.     getbox(x, y, w, h, b, w);
  538. }
  539.  
  540. void gl_copybox( int x1, int y1, int w, int h, int x2, int y2 ) {
  541. /* Doesn't handle clipping. */
  542.     if (MODETYPE == CONTEXT_PAGED) {
  543.         /* Paged primitive is not implemented. */
  544.         void *box;
  545.         box = alloca(w * h * BYTESPERPIXEL);
  546.         getbox(x1, y1, w, h, box, w);
  547.         putbox(x2, y2, w, h, box, w);
  548.         return;
  549.     }
  550.     copybox(x1, y1, w, h, x2, y2);
  551. }
  552.  
  553.  
  554. /* Miscellaneous functions */
  555.  
  556. void gl_clearscreen( int c ) {
  557.     gl_fillbox(0, 0, WIDTH, HEIGHT, c);
  558. }
  559.  
  560. int gl_rgbcolor( int r, int g, int b ) {
  561.     unsigned v;
  562.     switch (BITSPERPIXEL) {
  563.     case 8 :
  564.         /* assumes RGB palette at index 0-255 */
  565.         /* bits 0-2 = blue (3 bits) */
  566.         /*    3-5 = green (3 bits) */
  567.         /*    6-7 = red (2 bits) */
  568.         return (r & 0xc0) + ((g & 0xe0) >> 2) + (b >> 5);
  569.     case 24 :
  570.     case 32 :
  571.         v = (r << 16) + (g << 8) + b;
  572.         if (MODEFLAGS & MODEFLAG_32BPP_SHIFT8)
  573.             return v << 8;
  574.         return v;
  575.     case 15 :
  576.         return ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + (b >> 3);
  577.     case 16 :
  578.         return ((r & 0xf8) << 8) + ((g & 0xfc) << 3) + (b >> 3);
  579.     case 4 :
  580.         /* Now this is real fun. Map to standard EGA palette. */
  581.         v = 0;
  582.         if (b >= 64) v += 1;
  583.         if (g >= 64) v += 2;
  584.         if (r >= 64) v += 4;
  585.         if (b >= 192 || g >= 192 || r >= 192)
  586.             v += 8;
  587.         return v;
  588.     }
  589. }
  590.  
  591. void gl_setpixelrgb( int x, int y, int r, int g, int b ) {
  592. /* Color components range from 0 to 255 */
  593.     if (__clip && outside(x, y))
  594.         return;
  595.     setpixel(x, y, gl_rgbcolor(r, g, b));
  596. }
  597.  
  598. void gl_getpixelrgb( int x, int y, int *r, int *g, int *b ) {
  599.     unsigned c;
  600.     if (__clip && outside(x, y)) {
  601.         *r = *g = *b = -1;
  602.         return;
  603.     }
  604.     c = getpixel(x, y);
  605.     switch (BITSPERPIXEL) {
  606.     case 8 :
  607.         *b = (c & (1+2+4)) << 5;    /* bits 0-2 */
  608.         *g = (c & (8+16+32)) << 2;    /* bits 3-5 */
  609.         *r = (c & (64 + 128));        /* bits 6-7 */
  610.         break;
  611.     case 32 :
  612.         if (MODEFLAGS & MODEFLAG_32BPP_SHIFT8) {
  613.             *b = (c & 0xff00) >> 8;
  614.             *g = (c & 0xff0000) >> 16;
  615.             *r = c >> 24;
  616.             break;
  617.         }
  618.     case 24 :
  619.         *b = c & 0xff;
  620.         *g = (c & 0xff00) >> 8;
  621.         *r = c >> 16;
  622.         break;
  623.     case 15 :
  624.         *b = (c & (1+2+4+8+16)) << 3;
  625.         *g = (c & (32+64+128+256+512)) >> 2;
  626.         *r = (c & (1024+2048+4096+8192+16384)) >> 7;
  627.         break;
  628.     case 16 :
  629.         *b = (c & (1+2+4+8+16)) << 3;
  630.         *g = (c & (32+64+128+256+512+1024)) >> 3;
  631.         *r = (c & (2048+4096+8192+16384+32768)) >> 8;
  632.         break;
  633.     case 4 :
  634.         *b = (c & 1) * ((c & 8) ? 255 : 128);
  635.         *g = (c & 2) * ((c & 8) ? 255 : 128);
  636.         *r = (c & 4) * ((c & 8) ? 255 : 128);
  637.         break;
  638.     }
  639. }
  640.  
  641. void gl_setdisplaystart( int x, int y ) {
  642.     vga_setdisplaystart(y * BYTEWIDTH + x * BYTESPERPIXEL);
  643. }
  644.  
  645.  
  646. /* Screen copying */
  647.  
  648. void gl_setscreenoffset( int o ) {
  649.     screenoffset = o;
  650. }
  651.  
  652. int gl_enablepageflipping( GraphicsContext *gc ) {
  653.     if (gc->modeflags & MODEFLAG_PAGEFLIPPING_CAPABLE) {
  654.         gc->modeflags |= MODEFLAG_PAGEFLIPPING_ENABLED;
  655.     }
  656.     if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_CAPABLE) {
  657.         gc->modeflags &= ~(MODEFLAG_PAGEFLIPPING_ENABLED);
  658.         gc->modeflags |= MODEFLAG_TRIPLEBUFFERING_ENABLED;
  659.     }
  660.     gc->flippage = 0;
  661.     if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_ENABLED)
  662.         return 3;
  663.     if (gc->modeflags & MODEFLAG_PAGEFLIPPING_ENABLED)
  664.         return 2;
  665.     return 0;
  666. }
  667.  
  668. void gl_copyscreen( GraphicsContext *gc ) {
  669.     int size;
  670.     void *svp, *dvp;
  671.  
  672.     if (gc->modeflags & MODEFLAG_PAGEFLIPPING_ENABLED)
  673.         gc->flippage ^= 1;
  674.     if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_ENABLED)
  675.         gc->flippage = (gc->flippage + 1) % 3;
  676.     if (gc->modeflags & (MODEFLAG_PAGEFLIPPING_ENABLED |
  677.     MODEFLAG_TRIPLEBUFFERING_ENABLED)) {
  678.         /* Calculate screen offset in bytes. */
  679.         screenoffset = gc->bytewidth * HEIGHT * gc->flippage;
  680.         if (gc->modeflags & MODEFLAG_FLIPPAGE_BANKALIGNED)
  681.             screenoffset = ((screenoffset + 0xffff) & ~0xffff);
  682.     }
  683.  
  684.     if (gc->modetype == CONTEXT_MODEX) {
  685.         vga_copytoplanar256(VBUF, BYTEWIDTH, screenoffset / 4,
  686.             gc->bytewidth / 4, WIDTH, HEIGHT);
  687.         goto end;
  688.     }
  689.     if (gc->modetype == CONTEXT_PLANAR16) {
  690.         if (WIDTH == 1024 && HEIGHT >= 512 &&
  691.         ((screenoffset / 8) & 0xffff) == 0) {
  692.             /* Kludge to allow 1024x768x16 with page flipping. */
  693.             int page;
  694.             page = (screenoffset / 8) >> 16;
  695.             vga_setpage(page);
  696.             vga_copytoplanar16(VBUF, BYTEWIDTH, 0,
  697.                 gc->bytewidth / 8, WIDTH, 512);
  698.             vga_setpage(page + 1);
  699.             vga_copytoplanar16(VBUF + WIDTH * 512, BYTEWIDTH,
  700.                 0, gc->bytewidth / 8, WIDTH, HEIGHT - 512);
  701.             return;
  702.         }
  703.         if (WIDTH * HEIGHT >= 512 * 1024)
  704.             /* We don't handle banking. */
  705.             return;
  706.  
  707.         vga_copytoplanar16(VBUF, BYTEWIDTH, screenoffset / 8,
  708.             gc->bytewidth / 8, WIDTH, HEIGHT);
  709.         goto end;
  710.     }
  711.     if (BYTESPERPIXEL == 4 && gc->bytesperpixel == 3) {
  712.         /* Special case. */
  713.         int soffset, doffset;
  714.         if (BYTEWIDTH / 4 != gc->bytewidth / 3) {
  715.             /* Even more special case for physical truecolor */
  716.             /* modes that have extra scanline padding. */
  717.             /* This has the effect of slowing down */
  718.             /* '3d' in some truecolor modes on ATI mach32. */
  719.             gl_copyboxtocontext(0, 0, WIDTH, HEIGHT, gc, 0, 0);
  720.             goto end;
  721.         }
  722.         soffset = 0;
  723.         doffset = screenoffset;
  724.         size = WIDTH * HEIGHT;
  725.         while (soffset / 4 < size) {
  726.             int schunk, dchunk;
  727.                         int count;
  728.                         schunk = driver_setread(&__currentcontext, soffset, &svp);
  729.             dchunk = driver_setwrite(gc, doffset, &dvp);
  730.             if (dchunk == 1) {
  731.                 /* One byte left in segment. */
  732.                 int pix;
  733.                 pix = *(unsigned *)svp;    /* 32-bit pixel */
  734.                 *(unsigned char *)dvp = pix;
  735.                 dchunk = driver_setwrite(gc, doffset + 1, &dvp);
  736.                 *(unsigned short *)dvp = pix >> 8;
  737.                 count = 1;    /* 1 pixel handled. */
  738.             }
  739.             else
  740.             if (dchunk == 2) {
  741.                 /* Two bytes left. */
  742.                 int pix;
  743.                 pix = *(unsigned *)svp;    /* 32-bit pixel */
  744.                 *(unsigned short *)dvp = pix;
  745.                 dchunk = driver_setwrite(gc, doffset + 2, &dvp);
  746.                 *(unsigned char *)dvp = pix >> 16;
  747.                 count = 1;    /* 1 pixel handled. */
  748.             }
  749.             else {
  750.                 count = min(min(schunk / 4, dchunk / 3),
  751.                     size - (soffset / 4));
  752.                 memcpy4to3(dvp, svp, count);
  753.             }
  754.             soffset += count * 4;
  755.             doffset += count * 3;
  756.         }
  757.         goto end;
  758.     }
  759.     if (BYTESPERPIXEL == 4 && gc->bytesperpixel == 4 &&
  760.     (gc->modeflags & MODEFLAG_32BPP_SHIFT8)) {
  761.         int soffset = 0;
  762.         int doffset = screenoffset;
  763.         size = SCREENSIZE(__currentcontext);
  764.         while (soffset < size) {
  765.             int schunk, dchunk;
  766.             int count;
  767.             schunk = driver_setread(&__currentcontext, soffset, &svp);
  768.             dchunk = driver_setwrite(gc, doffset, &dvp);
  769.             count = min(min(schunk, dchunk), (size - soffset));
  770.             memcpy32shift8(dvp, svp, count / 4);
  771.             soffset += count;
  772.             doffset += count;
  773.         }
  774.     }
  775.     else {
  776.         int soffset = 0;
  777.         int doffset = screenoffset;
  778.         size = SCREENSIZE(__currentcontext);
  779.         while (soffset < size) {
  780.             int schunk, dchunk;
  781.             int count;
  782.             schunk = driver_setread(&__currentcontext, soffset, &svp);
  783.             dchunk = driver_setwrite(gc, doffset, &dvp);
  784.             count = min(min(schunk, dchunk), (size - soffset));
  785.             __memcpy(dvp, svp, count);
  786.             soffset += count;
  787.             doffset += count;
  788.         }
  789.     }
  790.  
  791. end:
  792.     if (gc->modeflags & (MODEFLAG_PAGEFLIPPING_ENABLED |
  793.     MODEFLAG_TRIPLEBUFFERING_ENABLED)) {
  794.         GraphicsContext save;
  795.         /* setdisplaystart will use BYTEWIDTH of the virtual screen, */
  796.         /* which is what we want since vga_setdisplaystart is */
  797.         /* defined in terms of pixel offset (except for hicolor */
  798.         /* modes, which are defined in terms of bytes). */
  799.         gl_getcontext(&save);
  800.         gl_setcontext(gc);
  801.         if (gc->modeflags & MODEFLAG_FLIPPAGE_BANKALIGNED)
  802.             vga_setdisplaystart(screenoffset);
  803.         else
  804.             gl_setdisplaystart(0, gc->height * gc->flippage);
  805.         gl_setcontext(&save);
  806.         /* For page flipping, it might be appropriate to add a */
  807.         /* waitverticalretrace here. */
  808.     }
  809.     screenoffset = 0;
  810. }
  811.  
  812. void gl_copyboxtocontext( int x1, int y1, int w, int h, GraphicsContext *gc,
  813. int x2, int y2 ) {
  814. /* This is now reasonably efficient if clipping is not enabled. */
  815.     void *buf;
  816.     GraphicsContext save;
  817.     gl_getcontext(&save);
  818.     if ((MODETYPE == CONTEXT_LINEAR || MODETYPE == CONTEXT_VIRTUAL) &&
  819.     (BYTESPERPIXEL == gc->bytesperpixel) &&
  820.     !__clip && !gc->clip) {
  821.         #ifdef DLL_CONTEXT_SHADOW
  822.         __currentcontext = *gc;
  823.         #else
  824.         gl_setcontext(gc);
  825.         #endif
  826.         putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, save.vbuf +
  827.             y1 * save.bytewidth + x1 * BYTESPERPIXEL,
  828.             save.bytewidth);
  829.         goto end;
  830.     }
  831.     buf = alloca(w * h * BYTESPERPIXEL);
  832.     gl_getbox(x1, y1, w, h, buf);
  833.     #ifdef DLL_CONTEXT_SHADOW
  834.     __currentcontext = *gc;
  835.     #else
  836.     gl_setcontext(gc);
  837.     #endif
  838.  
  839.     if (save.bytesperpixel == 4 && gc->bytesperpixel == 3) {
  840.         /* Special case conversion from 32-bit virtual screen to */
  841.         /* 24-bit truecolor framebuffer. */
  842.         if (gc->modetype == CONTEXT_PAGED || gc->clip) {
  843.             /* For paged modes or clipping, use another buffer. */
  844.             void *buf2;
  845.             buf2 = alloca(w * h * 3);
  846.             memcpy4to3(buf2, buf, w * h);
  847.             gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h,
  848.                 buf2);
  849.         }
  850.         else
  851.             /* No clipping, linear. */
  852.             driver24_putbox32(x2, y2, w, h, buf, w);
  853.     }
  854.     else    /* Contexts assumed to have same pixel size. */
  855.         gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, buf);
  856.  
  857. end:
  858.     #ifdef DLL_CONTEXT_SHADOW
  859.     __currentcontext = save;
  860.     #else
  861.     gl_setcontext(&save);
  862.     #endif
  863. }
  864.  
  865. void gl_copyboxfromcontext( GraphicsContext *gc, int x1, int y1, int w, int h,
  866. int x2, int y2 ) {
  867.     void *buf;
  868.     GraphicsContext save;
  869.     if ((gc->modetype == CONTEXT_LINEAR || gc->modetype == CONTEXT_VIRTUAL) &&
  870.     (BYTESPERPIXEL == gc->bytesperpixel) &&
  871.     !__clip && !gc->clip) {
  872.         putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, gc->vbuf +
  873.             y1 * gc->bytewidth + x1 * BYTESPERPIXEL,
  874.             gc->bytewidth);
  875.         return;
  876.     }
  877.     gl_getcontext(&save);
  878.     #ifdef DLL_CONTEXT_SHADOW
  879.     __currentcontext = *gc;
  880.     #else
  881.     gl_setcontext(gc);
  882.     #endif
  883.     buf = alloca(w * h * BYTESPERPIXEL);
  884.     gl_getbox(x1, y1, w, h, buf);
  885.     #ifdef DLL_CONTEXT_SHADOW
  886.     __currentcontext = save;
  887.     #else
  888.     gl_setcontext(&save);
  889.     #endif
  890.  
  891.     if (gc->bytesperpixel == 4 && save.bytesperpixel == 3) {
  892.         /* Special case conversion from 32-bit virtual screen to */
  893.         /* 24-bit truecolor framebuffer. */
  894.         if (save.modetype == CONTEXT_PAGED || save.clip) {
  895.             /* For paged modes or clipping, use another buffer. */
  896.             void *buf2;
  897.             buf2 = alloca(w * h * 3);
  898.             memcpy4to3(buf2, buf, w * h);
  899.             gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h,
  900.                 buf2);
  901.         }
  902.         else
  903.             /* No clipping, linear. */
  904.             driver24_putbox32(x2, y2, w, h, buf, w);
  905.     }
  906.     else    /* Contexts assumed to have same pixel size. */
  907.         gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, buf);
  908. }
  909.