home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gs252src.zip / GS252 / GDEVPCFB.C < prev    next >
C/C++ Source or Header  |  1992-09-18  |  24KB  |  921 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevpcfb.c */
  21. /* IBM PC EGA and VGA display drivers for Ghostscript */
  22. #include "dos_.h"
  23. typedef union REGS registers;
  24. /* This is fundamentally an EGA driver with some parameters */
  25. /* that allow it to drive larger displays. */
  26. #include "memory_.h"
  27. #include "gx.h"
  28. #include "gserrors.h"
  29. #include "gxdevice.h"
  30. #include "gdevpcfb.h"
  31.  
  32. /* Macro for casting gx_device argument */
  33. #define fb_dev ((gx_device_ega *)dev)
  34.  
  35. /* Procedure record */
  36. private gx_device_procs ega_procs = {
  37.     ega_open,
  38.     gx_default_get_initial_matrix,
  39.     gx_default_sync_output,
  40.     gx_default_output_page,
  41.     ega_close,
  42.     ega_map_rgb_color,
  43.     ega_map_color_rgb,
  44.     ega_fill_rectangle,
  45.     ega_tile_rectangle,
  46.     ega_copy_mono,
  47.     ega_copy_color,
  48.     gx_default_draw_line,
  49.     ega_get_bits,
  50.     gx_default_get_props,
  51.     gx_default_put_props
  52. };
  53.  
  54. /* All the known instances */
  55.         /* EGA */
  56. gx_device_ega gs_ega_device =
  57.     ega_device("ega", ega_procs, 80, 350, 48.0/35.0, 0x10);
  58.         /* VGA */
  59. gx_device_ega gs_vga_device =
  60.     ega_device("vga", ega_procs, 80, 480, 1.0, 0x12);
  61.         /* Trident SuperVGA, 800x600, 16-color mode */
  62. gx_device_ega gs_tvga16_device =
  63.     ega_device("tvga16", ega_procs, 100, 600, 1.0, 0x5b);
  64.         /* Tseng Labs SuperVGA, 800x600, 16-color mode */
  65. gx_device_ega gs_tseng16_device =
  66.     ega_device("tseng16", ega_procs, 100, 600, 1.0, 0x29);
  67.         /* EIZO MDB-10 */
  68. gx_device_ega gs_mdb10_device =
  69.     ega_device("mdb10", ega_procs, 128, 768, 1.0, 0x37);
  70.  
  71. /* Define the color spectrum */
  72. #define black 0
  73. #define blue 1
  74. #define green 2
  75. #define cyan 3
  76. #define red 4
  77. #define magenta 5
  78. #define brown 6
  79. #define white 7
  80. #define dgray 8                /* dark gray is not very usable */
  81. #define lblue 9
  82. #define lgreen 10
  83. #define lcyan 11
  84. #define lred 12
  85. #define lmagenta 13
  86. #define yellow 14
  87. #define bwhite 15
  88.  
  89. /* Forward declarations */
  90. private int ega_get_mode();
  91. private void ega_set_mode(int);
  92.  
  93. /* Save the EGA mode */
  94. private int ega_save_mode = -1;
  95.  
  96. /* Reinitialize the EGA for text mode */
  97. int
  98. ega_close(gx_device *dev)
  99. {    if ( ega_save_mode >= 0 ) ega_set_mode(ega_save_mode);
  100.     return 0;
  101. }
  102.  
  103. /* Map a r-g-b color to an EGA color code. */
  104. gx_color_index
  105. ega_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
  106.   gx_color_value b)
  107. {
  108. #define c12 (gx_max_color_value / 2)
  109. #define c13 (gx_max_color_value / 3)
  110. #define c23 (gx_max_color_value - c13)
  111. #define cmono() ((gx_color_index)mono_color[r >> (gx_color_value_bits - 2)])
  112. #if ega_bits_of_color == 0        /* monochrome */
  113.     static byte mono_color[4] = { black, white, white, bwhite };
  114.     return cmono();
  115. #else
  116. # if ega_bits_of_color == 1
  117.     static byte mono_color[4] = { black, white, white, bwhite };
  118.     if ( r == g && g == b )
  119.         return cmono();
  120.     return (gx_color_index)
  121.         ((r > c12 ? 4 : 0) |
  122.          (g > c12 ? 10 : 0) |
  123.          (b > c12 ? 1 : 0));
  124. # else
  125.     static byte g0[3][3] =
  126.      {{black,blue,lblue},{red,magenta,lmagenta},{lred,lmagenta,lmagenta}};
  127.     static byte g1[3][3] =
  128.      {{green,cyan,lcyan},{brown,white,lcyan},{yellow,yellow,lmagenta}};
  129.     static byte g2[3][3] =
  130.      {{lgreen,lgreen,lcyan},{lgreen,lgreen,lcyan},{yellow,yellow,bwhite}};
  131.     return (gx_color_index)
  132.         ((g >= c23 ? g2 : g >= c13 ? g1 : g0)
  133.          [r >= c23 ? 2 : r >= c13 ? 1 : 0]
  134.          [b >= c23 ? 2 : b >= c13 ? 1 : 0]);
  135. # endif
  136. #endif
  137. #undef c12
  138. #undef c13
  139. #undef c23
  140. }
  141.  
  142. /* Map a color code to r-g-b. */
  143. int
  144. ega_map_color_rgb(gx_device *dev, gx_color_index color,
  145.   gx_color_value prgb[3])
  146. {
  147. #define icolor (int)color
  148. #if rgb_max > 1
  149.     gx_color_value one =
  150.         (icolor & 8 ? gx_max_color_value : gx_max_color_value / 3);
  151. #else
  152. #  define one (gx_max_color_value / 2 + 1)
  153. #endif
  154.     prgb[0] = (icolor & 4 ? one : 0);
  155.     prgb[1] = (icolor & 2 ? one : 0);
  156.     prgb[2] = (icolor & 1 ? one : 0);
  157.     return 0;
  158. #undef one
  159. #undef icolor
  160. }
  161.  
  162. /* ------ Internal routines ------ */
  163.  
  164. /* Read the device mode */
  165. private int
  166. ega_get_mode()
  167. {    registers regs;
  168.     regs.h.ah = 0xf;
  169.     int86(0x10, ®s, ®s);
  170.     return regs.h.al;
  171. }
  172.  
  173. /* Set the device mode */
  174. private void
  175. ega_set_mode(int mode)
  176. {    registers regs;
  177.     regs.h.ah = 0;
  178.     regs.h.al = mode;
  179.     int86(0x10, ®s, ®s);
  180. }
  181.  
  182. /* Structure for operation parameters. */
  183. /* Note that this structure is known to assembly code. */
  184. /* Not all parameters are used for every operation. */
  185. typedef struct rop_params_s {
  186.     fb_ptr dest;            /* pointer to frame buffer */
  187.     int draster;            /* raster of frame buffer */
  188.     const byte far *src;        /* pointer to source data */
  189.     int sraster;            /* source raster */
  190.     int width;            /* width in bytes */
  191.     int height;            /* height in scan lines */
  192.     int shift;            /* amount to right shift source */
  193.     int invert;            /* 0 or -1 to invert source */
  194.     int data;            /* data for fill */
  195. } rop_params;
  196. typedef rop_params _ss *rop_ptr;
  197.  
  198. /* Assembly language routines */
  199.  
  200. #if USE_ASM
  201. void memsetcol(P1(rop_ptr)); /* dest, draster, height, data */
  202. #else
  203. #define memsetcol cmemsetcol
  204. private void
  205. cmemsetcol(rop_ptr rop)
  206. {    byte *addr = rop->dest;
  207.     int yc = rop->height;
  208.     byte data = rop->data;
  209.     int draster = rop->draster;
  210.     while ( yc-- )
  211.      { byte_discard(*addr);
  212.        *addr = data;
  213.        addr += draster;
  214.      }
  215. }
  216. #endif
  217.  
  218. #if USE_ASM
  219. void memsetrect(P1(rop_ptr)); /* dest, draster, width, height, data */
  220. #else
  221. #define memsetrect cmemsetrect
  222. private void
  223. cmemsetrect(rop_ptr rop)
  224. {    int yc = rop->height;
  225.     int width = rop->width;
  226.     if ( yc <= 0 || width <= 0 ) return;
  227.        {    byte far *addr = rop->dest;
  228.         byte data = rop->data;
  229.         if ( width > 5 )    /* use memset */
  230.            {    int skip = rop->draster;
  231.             do
  232.                {    memset(addr, data, width);
  233.                 addr += skip;
  234.                }
  235.             while ( --yc );
  236.            }
  237.         else            /* avoid the fixed overhead */
  238.            {    int skip = rop->draster - width;
  239.             do
  240.                {    int cnt = width;
  241.                 do { *addr++ = data; } while ( --cnt );
  242.                 addr += skip;
  243.                }
  244.             while ( --yc );
  245.            }
  246.        }
  247. }
  248. #endif
  249.  
  250. #if USE_ASM
  251. void memrwcol(P1(rop_ptr)); /* dest, draster, src, sraster, height, shift, invert */
  252. #  define memrwcol0(rop) memrwcol(rop)    /* same except shift = 0 */
  253. #else
  254. #  define memrwcol cmemrwcol
  255. #  define memrwcol0 cmemrwcol0
  256. private void
  257. cmemrwcol(rop_ptr rop)
  258. {    byte far *dp = rop->dest;
  259.     const byte far *sp = rop->src;
  260.     int yc = rop->height;
  261.     int shift = rop->shift;
  262.     byte invert = rop->invert;
  263.     int sraster = rop->sraster, draster = rop->draster;
  264.     while ( yc-- )
  265.      { byte_discard(*dp);
  266.        *dp = ((*sp >> shift) + (*sp << (8 - shift))) ^ invert;
  267.        dp += draster, sp += sraster;
  268.      }
  269. }
  270. private void
  271. cmemrwcol0(rop_ptr rop)
  272. {    byte far *dp = rop->dest;
  273.     const byte far *sp = rop->src;
  274.     int yc = rop->height;
  275.     byte invert = rop->invert;
  276.     int sraster = rop->sraster, draster = rop->draster;
  277.     if ( yc > 0 ) do
  278.      { byte_discard(*dp);
  279.        *dp = *sp ^ invert;
  280.        dp += draster, sp += sraster;
  281.      }
  282.     while ( --yc );
  283. }
  284. #endif
  285.  
  286. #if USE_ASM
  287. void memrwcol2(P1(rop_ptr)); /* dest, draster, src, sraster, height, shift, invert */
  288. #else
  289. #define memrwcol2 cmemrwcol2
  290. private void
  291. cmemrwcol2(rop_ptr rop)
  292. {    byte far *dp = rop->dest;
  293.     const byte far *sp = rop->src;
  294.     int yc = rop->height;
  295.     int shift = rop->shift;
  296.     byte invert = rop->invert;
  297.     int sraster = rop->sraster, draster = rop->draster;
  298.     while ( yc-- )
  299.      { byte_discard(*dp);
  300.        *dp = ((sp[1] >> shift) + (*sp << (8 - shift))) ^ invert;
  301.        dp += draster, sp += sraster;
  302.      }
  303. }
  304. #endif
  305.  
  306. /* Forward definitions */
  307. int ega_write_dot(P4(gx_device *, int, int, gx_color_index));
  308. private void near fill_rectangle(P4(rop_ptr, int, int, int));
  309. private void near fill_row_only(P4(byte far *, int, int, int));
  310.  
  311. /* Clean up after writing */
  312. #define dot_end()\
  313.   set_g_mask(0xff)            /* all bits on */
  314.  
  315. /* Initialize the EGA for graphics mode */
  316. int
  317. ega_open(gx_device *dev)
  318. {    /* Adjust the device resolution. */
  319.     /* This is a hack, pending refactoring of the put_props machinery. */
  320.     switch ( fb_dev->video_mode )
  321.     {
  322.     case 0x10:    /* EGA */
  323.         gx_device_adjust_resolution(dev, 640, 350, 1); break;
  324.     case 0x12:    /* VGA */
  325.         gx_device_adjust_resolution(dev, 640, 480, 1); break;
  326.     case 0x5b:    /* Trident */
  327.     case 0x29:    /* Tseng */
  328.         gx_device_adjust_resolution(dev, 800, 600, 1); break;
  329.     case 0x37:    /* EIZO */
  330.         gx_device_adjust_resolution(dev, 1024, 768, 1); break;
  331.     }
  332.     if ( ega_save_mode < 0 ) ega_save_mode = ega_get_mode();
  333.     ega_set_mode(fb_dev->video_mode);
  334.     set_s_map(-1);            /* enable all maps */
  335.     return 0;
  336. }
  337.  
  338. /* Write a dot using the EGA color codes. */
  339. /* This doesn't have to be efficient. */
  340. int
  341. ega_write_dot(gx_device *dev, int x, int y, gx_color_index color)
  342. {    byte data[4];
  343.     data[0] = (byte)color;
  344.     return ega_copy_color(dev, data, 1, 4, gx_no_bitmap_id, x, y, 1, 1);
  345. }
  346.  
  347. /* Macro for testing bit-inclusion */
  348. #define bit_included_in(x,y) !((x)&~(y))
  349.  
  350. /* Copy a monochrome bitmap.  The colors are given explicitly. */
  351. /* Color = gx_no_color_index means transparent (no effect on the image). */
  352. int
  353. ega_copy_mono(gx_device *dev,
  354.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  355.   int x, int y, int w, int h, gx_color_index izero, gx_color_index ione)
  356. {    rop_params params;
  357. #define czero (int)izero
  358. #define cone (int)ione
  359.     int dleft, count;
  360.     byte mask, rmask;
  361.     fb_ptr save_dest;
  362.     int other_color = -1;
  363.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  364.     while ( h > fb_dev->max_rop_height )
  365.        {    unsigned mrh = fb_dev->max_rop_height;
  366.         int code = ega_copy_mono(dev, base, sourcex, raster, id,
  367.                 x, y, w, mrh, izero, ione);
  368.         if ( code != 0 ) return code;
  369.         base = (byte *)((byte huge *)base +
  370.                 raster * (long)mrh);
  371.         id = gx_no_bitmap_id;
  372.         y += mrh;
  373.         h -= mrh;
  374.        }
  375.     params.dest = mk_fb_ptr(x, y);
  376.     params.draster = fb_dev->raster;
  377.     params.src = base + (sourcex >> 3);
  378.     params.sraster = raster;
  379.     params.height = h;
  380.     params.shift = (x - sourcex) & 7;
  381.     /* Analyze the 16 possible cases: each of izero and ione may be */
  382.     /* 0, 0xf, transparent, or some other color. */
  383.     switch ( czero )
  384.        {
  385.     case no_color:
  386.         switch ( cone )
  387.            {
  388.         default:        /* (T, other) */
  389.             /* Must do 2 passes */
  390.             other_color = cone;
  391.             save_dest = params.dest;
  392.             /* falls through */
  393.         case 0:            /* (T, 0) */
  394.             set_g_function(gf_AND);
  395.             params.invert = -1;
  396.             break;
  397.         case 0xf:        /* (T, 0xf) */
  398.             set_g_function(gf_OR);
  399.             params.invert = 0;
  400.             break;
  401.         case no_color:        /* (T, T) */
  402.             return 0;    /* nothing to do */
  403.            }
  404.         break;
  405.     case 0:
  406.         params.invert = 0;
  407.         switch ( cone )
  408.            {
  409.         default:        /* (0, other) */
  410.             set_g_const(0);
  411.             set_g_const_map(cone ^ 0xf);
  412.             /* falls through */
  413.         case 0xf:        /* (0, 0xf) */
  414.             break;
  415.         case no_color:        /* (0, T) */
  416.             set_g_function(gf_AND);
  417.             break;
  418.            }
  419.         break;
  420.     case 0xf:
  421.         params.invert = -1;
  422.         switch ( cone )
  423.            {
  424.         case 0:            /* (0xf, 0) */
  425.             break;
  426.         default:        /* (0xf, other) */
  427.             set_g_const(0xf);
  428.             set_g_const_map(cone);
  429.             break;
  430.         case no_color:        /* (0xf, T) */
  431.             set_g_function(gf_OR);
  432.             /* falls through */
  433.            }
  434.         break;
  435.     default:
  436.         switch ( cone )
  437.            {
  438.         default:        /* (other, not T) */
  439.             if ( bit_included_in(czero, cone) )
  440.                {    set_g_const(czero);
  441.                 set_g_const_map(czero ^ cone ^ 0xf);
  442.                 params.invert = 0;
  443.                 break;
  444.                }
  445.             else if ( bit_included_in(cone, czero) )
  446.                {    set_g_const(cone);
  447.                 set_g_const_map(cone ^ czero ^ 0xf);
  448.                 params.invert = -1;
  449.                 break;
  450.                }
  451.             /* No way around it, fill with one color first. */
  452.             save_dest = params.dest;
  453.             fill_rectangle((rop_ptr)¶ms, x & 7, w, cone);
  454.             params.dest = save_dest;
  455.             set_g_function(gf_XOR);
  456.             set_s_map(czero ^ cone);
  457.             other_color = -2;    /* must reset s_map at end */
  458.             params.invert = -1;
  459.             break;
  460.         case no_color:        /* (other, T) */
  461.             /* Must do 2 passes */
  462.             other_color = czero;
  463.             save_dest = params.dest;
  464.             set_g_function(gf_AND);
  465.             params.invert = 0;
  466.             break;
  467.            }
  468.         break;
  469.        }
  470.     /* Actually copy the bits. */
  471.     dleft = 8 - (x & 7);
  472.     mask = 0xff >> (8 - dleft);
  473.     count = w - dleft;
  474.     if ( count < 0 )
  475.         mask -= mask >> w,
  476.         rmask = 0;
  477.     else
  478.         rmask = 0xff00 >> (count & 7);
  479.     /* params: dest, src, sraster, height, shift, invert */
  480.     /* Smashes params.src, params.dest, count. */
  481. copy:    set_g_mask(mask);
  482.     if ( params.shift == 0 )    /* optimize the aligned case */
  483.        {    /* Do left column */
  484.         memrwcol0((rop_ptr)¶ms);
  485.         /* Do center */
  486.         if ( (count -= 8) >= 0 )
  487.            {    out_g_mask(0xff);
  488.             do
  489.                {    params.src++, params.dest++;
  490.                 memrwcol0((rop_ptr)¶ms);
  491.                }
  492.             while ( (count -= 8) >= 0 );
  493.            }
  494.         /* Do right column */
  495.         if ( rmask )
  496.            {    params.src++, params.dest++;
  497.             out_g_mask(rmask);
  498.             memrwcol0((rop_ptr)¶ms);
  499.            }
  500.        }
  501.     else
  502.        {    /* Do left column */
  503.         int sleft = 8 - (sourcex & 7);
  504.         if ( sleft >= dleft )
  505.            {    /* Source fits in one byte */
  506.             memrwcol((rop_ptr)¶ms);
  507.            }
  508.         else if ( w <= sleft )
  509.            {    /* Source fits in one byte, thin case */
  510.             memrwcol((rop_ptr)¶ms);
  511.             goto fin;
  512.            }
  513.         else
  514.            {    memrwcol2((rop_ptr)¶ms);
  515.             params.src++;
  516.            }
  517.         /* Do center */
  518.         if ( (count -= 8) >= 0 )
  519.            {    out_g_mask(0xff);
  520.             do
  521.                {    params.dest++;
  522.                 memrwcol2((rop_ptr)¶ms);
  523.                 params.src++;
  524.                }
  525.             while ( (count -= 8) >= 0 );
  526.            }
  527.         /* Do right column */
  528.         if ( rmask )
  529.            {    out_g_mask(rmask);
  530.             params.dest++;
  531.             if ( count + 8 <= params.shift )
  532.                 memrwcol((rop_ptr)¶ms);
  533.             else
  534.                 memrwcol2((rop_ptr)¶ms);
  535.            }
  536.        }
  537. fin:    if ( other_color != -1 )
  538.        {    if ( other_color >= 0 )
  539.            {    /* Do the second pass on (T, other) or (other, T). */
  540.             count = w - dleft;
  541.             params.src = base + (sourcex >> 3);
  542.             params.dest = save_dest;
  543.             params.invert ^= -1;
  544.             set_s_map(other_color);
  545.             set_g_function(gf_OR);
  546.             other_color = -2;
  547.             goto copy;
  548.            }
  549.         else
  550.            {    /* Finished second pass, restore s_map */
  551.             set_s_map(-1);
  552.            }
  553.        }
  554.     set_g_function(gf_WRITE);
  555.     set_g_const_map(0);
  556.     dot_end();
  557.     return 0;
  558. #undef czero
  559. #undef cone
  560. }
  561.  
  562. /* Copy a color pixelmap.  This is just like a bitmap, */
  563. /* except that each pixel takes 4 bits instead of 1. */
  564. int
  565. ega_copy_color(gx_device *dev,
  566.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  567.   int x, int y, int w, int h)
  568. {    const byte *line = base + (sourcex >> 1);
  569.     unsigned lmask = 0x80 >> (x & 7);
  570.     int bitx = sourcex & 1;
  571.     int ex = w + bitx;
  572.     fb_ptr fbline;
  573.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  574.     while ( h > fb_dev->max_rop_height )
  575.        {    unsigned mrh = fb_dev->max_rop_height;
  576.         int code = ega_copy_color(dev, base, sourcex, raster, id,
  577.                 x, y, w, mrh);
  578.         if ( code != 0 ) return code;
  579.         base = (const byte *)((const byte huge *)base +
  580.                 raster * (long)mrh);
  581.         id = gx_no_bitmap_id;
  582.         y += mrh;
  583.         h -= mrh;
  584.        }
  585.     fbline = mk_fb_ptr(x, y);
  586.     set_g_mode(gm_FILL);
  587.     select_g_mask();
  588.     while ( --h >= 0 )
  589.     {    const byte *bptr = line;
  590.         int px = bitx;
  591.         /* Turbo C will put an unsigned in a register, */
  592.         /* but not a byte! */
  593.         register unsigned mask = lmask;
  594.         fb_ptr fbptr = fbline;
  595.         do
  596.            {    byte_discard(*fbptr);    /* latch frame buffer data */
  597.             out_g_mask(mask);
  598.             *fbptr = (px & 1 ? *bptr++ & 0xf : *bptr >> 4);
  599.             if ( (mask >>= 1) == 0 )
  600.                 mask = 0x80, fbptr++;
  601.            }
  602.         while ( ++px < ex );
  603.         line += raster;
  604.         fbline += fb_dev->raster;
  605.     }
  606.     set_g_mode(gm_DATA);
  607.     dot_end();
  608.     return 0;
  609. }
  610.  
  611. /* Fill a rectangle. */
  612. int
  613. ega_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  614.   gx_color_index color)
  615. {    rop_params params;
  616.     fit_fill(dev, x, y, w, h);
  617.     while ( h > fb_dev->max_rop_height )
  618.        {    unsigned mrh = fb_dev->max_rop_height;
  619.         int code = ega_fill_rectangle(dev,
  620.             x, y, w, mrh, color);
  621.         if ( code != 0 ) return code;
  622.         y += mrh;
  623.         h -= mrh;
  624.        }
  625.     params.dest = mk_fb_ptr(x, y);
  626.     if ( h == 1 )
  627.         fill_row_only(params.dest, x & 7, w, (int)color);
  628.     else
  629.        {    params.draster = fb_dev->raster;
  630.         params.height = h;
  631.         fill_rectangle((rop_ptr)¶ms, x & 7, w, (int)color);
  632.         dot_end();
  633.        }
  634.     return 0;
  635. }
  636.  
  637. /* Tile a rectangle.  Note that the two colors must both be supplied, */
  638. /* i.e. neither one can be gx_no_color_index (transparent): */
  639. /* a transparent color means that the tile is colored, not a mask. */
  640. int
  641. ega_tile_rectangle(gx_device *dev, const gx_bitmap *tile,
  642.   int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
  643.   int px, int py)
  644. #define zero (int)czero
  645. #define one (int)cone
  646. {    rop_params params;
  647.     int xmod, width_bytes;
  648.     int tile_height = tile->size.y;
  649.     int xbit;
  650.     int lcount;
  651.     int mask, rmask;
  652.     byte narrow;
  653.     byte again;
  654.     int const_bits, maps;
  655.     int ymod, yleft;
  656.     fit_fill(dev, x, y, w, h);
  657.     while ( h > fb_dev->max_rop_height )
  658.        {    int mod_height =
  659.             fb_dev->max_rop_height / tile_height * tile_height;
  660.         int code = ega_tile_rectangle(dev, tile,
  661.             x, y, w, mod_height, czero, cone, px, py);
  662.         if ( code != 0 ) return code;
  663.         y += mod_height;
  664.         h -= mod_height;
  665.        }
  666.     /* We only handle the easiest cases directly. */
  667.     if ( (tile->size.x & 7) || one == -1 || zero == -1 || px || py )
  668.         return gx_default_tile_rectangle(dev, tile, x, y, w, h,
  669.             czero, cone, px, py);
  670.     /* Following is similar to aligned case of copy_mono */    
  671.     params.dest = mk_fb_ptr(x, y);
  672.     params.draster = fb_dev->raster;
  673.     params.sraster = tile->raster;
  674.     params.shift = 0;
  675.     xbit = x & 7;
  676.     /* Set up the graphics registers */
  677.     const_bits = (zero ^ one) ^ 0xf;
  678.     if ( const_bits )
  679.        {    set_g_const(zero);    /* either color will do */
  680.         set_g_const_map(const_bits);
  681.        }
  682.     if ( (maps = zero & ~one) != 0 )
  683.        {    set_s_map(maps += const_bits);
  684.         params.invert = -1;
  685.         again = one & ~zero;
  686.        }
  687.     else
  688.        {    maps = one & ~zero;
  689.         set_s_map(maps += const_bits);
  690.         params.invert = 0;
  691.         again = 0;
  692.        }
  693.     xmod = (x % tile->size.x) >> 3;
  694.     width_bytes = tile->size.x >> 3;
  695.     mask = 0xff >> xbit;
  696.     if ( w + xbit <= 8 )
  697.         mask -= mask >> w,
  698.         rmask = 0,
  699.         narrow = 1;
  700.     else
  701.        {    rmask = (0xff00 >> ((w + x) & 7)) & 0xff;
  702.         if ( xbit )    w += xbit - 8;
  703.         else        mask = 0, --xmod, --params.dest;
  704.         narrow = 0;
  705.        }
  706.     ymod = y % tile_height;
  707. tile:    yleft = tile_height - ymod;
  708.     params.src = tile->data + ymod * params.sraster + xmod;
  709.     lcount = h;
  710.     if ( narrow )            /* Optimize narrow case */
  711.        {    set_g_mask(mask);
  712.         if ( lcount > yleft )
  713.            {    params.height = yleft;
  714.             memrwcol0((rop_ptr)¶ms);
  715.             params.dest += yleft * params.draster;
  716.             params.src = tile->data + xmod;
  717.             params.height = tile_height;
  718.             lcount -= yleft;
  719.             while ( lcount >= tile_height )
  720.                {    memrwcol0((rop_ptr)¶ms);
  721.                 params.dest += tile_height * params.draster;
  722.                 lcount -= tile_height;
  723.                }
  724.            }
  725.         if ( lcount )
  726.            {    params.height = lcount;
  727.             memrwcol0((rop_ptr)¶ms);
  728.            }
  729.        }
  730.     else
  731.        {    fb_ptr line = params.dest;
  732.         int xpos = width_bytes - xmod;
  733.         while ( 1 )
  734.            {    int xleft = xpos;
  735.             int count = w;
  736.             params.height = (lcount > yleft ? yleft : lcount);
  737.             /* Do first byte, if not a full byte. */
  738.             if ( mask )
  739.                {    set_g_mask(mask);
  740.                 memrwcol0((rop_ptr)¶ms);
  741.                }
  742.             /* Do full bytes */
  743.             if ( (count -= 8) >= 0 )
  744.                {    set_g_mask(0xff);
  745.                 do
  746.                    {    if ( !--xleft )
  747.                         xleft = width_bytes,
  748.                         params.src -= width_bytes;
  749.                     ++params.src, ++params.dest;
  750.                     memrwcol0((rop_ptr)¶ms);
  751.                    }
  752.                 while ( (count -= 8) >= 0 );
  753.                }
  754.             /* Do last byte */
  755.             if ( rmask )
  756.                {    if ( !--xleft )
  757.                     xleft = width_bytes,
  758.                     params.src -= width_bytes;
  759.                 set_g_mask(rmask);
  760.                 ++params.src, ++params.dest;
  761.                 memrwcol0((rop_ptr)¶ms);
  762.                }
  763.             if ( (lcount -= params.height) == 0 ) break;
  764.             params.dest = line += params.height * params.draster;
  765.             params.src = tile->data + xmod;
  766.             yleft = tile_height;
  767.            }
  768.        }
  769.     /* Now do the second color if needed */
  770.     if ( again )
  771.        {    maps = again + const_bits;
  772.         set_s_map(maps);
  773.         again = 0;
  774.         params.dest = mk_fb_ptr(x, y);
  775.         if ( mask == 0 ) params.dest--;
  776.         params.invert = 0;
  777.         goto tile;
  778.        }
  779.     if ( maps != 0xf )
  780.         set_s_map(-1);
  781.     if ( const_bits )
  782.         set_g_const_map(0);
  783.     dot_end();
  784.     return 0;
  785. }
  786.  
  787. /* Read scan lines back from the frame buffer. */
  788. int
  789. ega_get_bits(gx_device *dev, int y, byte *data, uint size, int pad_to_word)
  790. {    /* We don't have to worry about padding, because we read back */
  791.     /* 4 bits per pixel and the frame buffer width is always */
  792.     /* a multiple of 8 pixels. */
  793.     uint bytes_per_row = dev->width >> 1;
  794.     uint count = min(dev->height - y, size / bytes_per_row);
  795.     int j, plane;
  796.     byte *drow = data;
  797.     memset(data, 0, size);
  798.     for ( j = count; j--; drow += bytes_per_row, y++ )
  799.       for ( plane = 0; plane < 4; plane++ )
  800.        {    fb_ptr src = mk_fb_ptr(0, y);
  801.         ushort *dest = (ushort *)drow;
  802.         int i;
  803.         /* Plane 0 is the least significant plane. */
  804.         /* We know we're on a little-endian machine.... */
  805.         static ushort spread4[16] =
  806.            {    0x0, 0x800, 0x8000, 0x8800,
  807.             0x8, 0x808, 0x8008, 0x8808,
  808.             0x80, 0x880, 0x8080, 0x8880,
  809.             0x88, 0x888, 0x8088, 0x8888
  810.            };
  811.         set_g_read_plane(plane);
  812.         for ( i = 0; i < dev->width; i += 8, src++, dest += 2 )
  813.            {    byte b = *src;
  814.             dest[0] = (dest[0] >> 1) + spread4[b >> 4];
  815.             dest[1] = (dest[1] >> 1) + spread4[b & 0xf];
  816.            }
  817.        }
  818.     return count;
  819. }
  820.  
  821. /* ------ Internal routines ------ */
  822.  
  823. /* Mask table for rectangle fill. */
  824. static byte rmask_tab[9] =
  825.    {    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
  826.    };
  827.  
  828. /* Fill a rectangle specified by pointer into frame buffer, */
  829. /* starting bit within byte, width, and height. */
  830. /* Smashes rop->dest. */
  831. private void near
  832. fill_rectangle(register rop_ptr rop, int bit, int w, int color)
  833.   /* rop: dest, draster, height */
  834. {    set_g_const(color);
  835.     set_g_const_map(0xf);
  836.     select_g_mask();
  837.     if ( bit + w <= 8 )
  838.        {    /* Less than one byte */
  839.         out_g_mask(rmask_tab[w] >> bit);
  840.         memsetcol(rop);
  841.        }
  842.     else
  843.        {    byte right_mask;
  844.         if ( bit )
  845.            {    out_g_mask(0xff >> bit);
  846.             memsetcol(rop);
  847.             rop->dest++;
  848.             w += bit - 8;
  849.            }
  850.         if ( w >= 8 )
  851.            {    out_g_mask(0xff);    /* all bits */
  852.             rop->width = w >> 3;
  853.             memsetrect(rop);
  854.             rop->dest += rop->width;
  855.             w &= 7;
  856.            }
  857.         if ( (right_mask = rmask_tab[w]) != 0 )
  858.            {    out_g_mask(right_mask);
  859.             memsetcol(rop);
  860.            }
  861.        }
  862.     set_g_const_map(0);
  863. }
  864.  
  865. /* Fill a single row specified by pointer into frame buffer, */
  866. /* starting bit within byte, and width; clean up afterwards. */
  867. #define r_m_w(ptr) (*(ptr))++        /* read & write, data irrelevant */
  868. private void near
  869. fill_row_only(byte far *dest, int bit, int w, int color)
  870.   /* rop: dest */
  871. {    if ( bit + w <= 8 )
  872.        {    /* Less than one byte. */
  873.         /* Optimize filling with black or white. */
  874.         switch ( color )
  875.         {
  876.         case 0:
  877.             set_g_mask(rmask_tab[w] >> bit);
  878.             *dest &= color;        /* read, then write 0s; */
  879.                 /* some compilers optimize &= 0 to a store. */
  880.             out_g_mask(0xff);        /* dot_end */
  881.             break;
  882.         case 0xf:
  883.             set_g_mask(rmask_tab[w] >> bit);
  884.             *dest |= 0xff;        /* read, then write 1s; */
  885.                 /* some compilers optimize &= 0 to a store. */
  886.             out_g_mask(0xff);        /* dot_end */
  887.             break;
  888.         default:
  889.             set_g_const(color);
  890.             set_g_const_map(0xf);
  891.             set_g_mask(rmask_tab[w] >> bit);
  892.             r_m_w(dest);
  893.             out_g_mask(0xff);        /* dot_end */
  894.             set_g_const_map(0);
  895.         }
  896.        }
  897.     else
  898.        {    byte right_mask;
  899.         int byte_count;
  900.         set_g_const(color);
  901.         set_g_const_map(0xf);
  902.         select_g_mask();
  903.         if ( bit )
  904.            {    out_g_mask(0xff >> bit);
  905.             r_m_w(dest);
  906.             dest++;
  907.             w += bit - 8;
  908.            }
  909.         byte_count = w >> 3;
  910.         if ( (right_mask = rmask_tab[w & 7]) != 0 )
  911.            {    out_g_mask(right_mask);
  912.             r_m_w(dest + byte_count);
  913.            }
  914.         out_g_mask(0xff);
  915.         if ( byte_count )
  916.            {    memset(dest, 0, byte_count);    /* data irrelevant */
  917.            }
  918.         set_g_const_map(0);
  919.        }
  920. }
  921.