home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gs252b.lzh / GS252B / GDEVVDI.C < prev    next >
Text File  |  1993-07-30  |  41KB  |  1,571 lines

  1. /* Copyright (C) 1991 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. /* gdevvdi.c */
  21.  
  22. /* Bitmapped screen device for the Atari ST. This driver contains
  23.  * portions of code originally written by Hauke Hess. This device
  24.  * uses the vdi for all screen operations. It recognizes and supports
  25.  * 1, 2, 4, and 8 bit color. Tim Gallivan 10/92.
  26.  */
  27.  
  28. /* For monochrome, Ghostscript produces a bitmap in memory which
  29.  * is referenced directly by 'base'. For color images, GS produces
  30.  * a bitmap at 'base' with each byte representing one pixel,
  31.  * regardless of how many bits the ST actually uses. The routine
  32.  * 'pack_to_plane()' copies the GS "packed" image format into the
  33.  * appropriate number of color planes, referenced by 'cbase'. The
  34.  * image in 'cbase' is then copied back to 'base' with the vdi routine
  35.  * 'vr_trnfm()', and is then copied to the screen. This is rather
  36.  * convoluted, but is needed for portability.
  37.  */
  38.  
  39. #include <stdio.h>
  40. #include <osbind.h>
  41. #include <gemdefs.h>
  42. #include <aesbind.h>
  43. #include <vdibind.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include "gdevprn.h"
  47. #include <math.h>
  48.  
  49. /* Define the default device parameters. */
  50.  
  51. #ifndef X_DPI
  52. #define X_DPI 80
  53. #endif
  54. #ifndef Y_DPI
  55. #define Y_DPI 80
  56. #endif
  57.  
  58. #define UL        (unsigned long)
  59. #define WIDTH_10THS    85
  60. #define HEIGHT_10THS    110
  61.  
  62. #define MIN(x, y) ((x <= y) ? x : y)
  63. #define MAX(x, y) ((x >= y) ? x : y)
  64.  
  65. /* Macros for casting the pdev argument */
  66.  
  67. #define ppdev ((gx_device_printer *)pdev)
  68. #define pmemdev ((gx_device_memory *)pdev)
  69.  
  70. #define W_FEATURES (NAME+CLOSER+MOVER+SIZER+FULLER+VSLIDE\
  71.             +HSLIDE+UPARROW+DNARROW+LFARROW+RTARROW)
  72. #define ABOUT    11
  73. #define NEXT    20
  74. #define QUIT    21
  75.  
  76. /* Menu bar when windows are enabled. */
  77.  
  78. OBJECT menu[] = {
  79.  
  80. /* 0 */  {-1,  1,  9, G_IBOX,  0, 0, 0L,                   0, 0, 80,  25},
  81. /* 1 */  { 9,  2,  2, G_BOX ,  0, 0, 0x1100L,              0, 0, 80, 513},
  82.  
  83. /* 2 */  { 1,  3,  4, G_IBOX,  0, 0, 0L,                   2, 0, 15, 769},
  84. /* 3 */  { 4, -1, -1, G_TITLE, 0, 0, UL" Desk ",           0, 0,  6, 769},
  85. /* 4 */  { 2, -1, -1, G_TITLE, 0, 0, UL" Display ",        6, 0,  9, 769},
  86. /* 5 */  { 6, -1, -1, G_TITLE, 0, DISABLED, UL"",         15, 0, 10, 769},
  87. /* 6 */  { 7, -1, -1, G_TITLE, 0, DISABLED, UL"",         25, 0, 10, 769},
  88. /* 7 */  { 8, -1, -1, G_TITLE, 0, DISABLED, UL"",         35, 0, 10, 769},
  89. /* 8 */  { 2, -1, -1, G_TITLE, 0, DISABLED, UL"",         45, 0, 10, 769},
  90.  
  91. /* 9 */  { 0,  10, 19, G_IBOX,  0, 0, 0L,                 0, 769, 80, 19},
  92.  
  93. /* 10 */  { 19, 11, 18, G_BOX ,  0, 0, 0xff1100L,            2, 0, 20, 8},
  94. /* 11 */  { 12, -1, -1, G_STRING ,  0, 0, UL"  About stvdi", 0, 0, 20, 1},
  95. /* 12 */  { 13, -1, -1, G_STRING ,  0, 0x08, UL" ------------------ ",  0, 1, 20, 1},
  96. /* 13 */  { 14, -1, -1, G_STRING ,  0, 0, UL"1",             0, 2, 20, 1},
  97. /* 14 */  { 15, -1, -1, G_STRING ,  0, 0, UL"2",             0, 3, 20, 1},
  98. /* 15 */  { 16, -1, -1, G_STRING ,  0, 0, UL"3",             0, 4, 20, 1},
  99. /* 16 */  { 17, -1, -1, G_STRING ,  0, 0, UL"4",             0, 5, 20, 1},
  100. /* 17 */  { 18, -1, -1, G_STRING ,  0, 0, UL"5",             0, 6, 20, 1},
  101. /* 18 */  { 10, -1, -1, G_STRING ,  0, 0, UL"6",             0, 7, 20, 1},
  102.  
  103. /* 19 */  {  9, 20, 21, G_BOX ,  0, 0, 0xff1100L,              8, 0, 14, 2},
  104. /* 20 */  { 21, -1, -1, G_STRING ,  0, 0, UL"  Next Page ❎n", 0, 0, 14, 1},
  105. /* 21 */  { 19, -1, -1, G_STRING ,  0, 0, UL"  Quit      ❎q", 0, 1, 14, 1},
  106. /* 22 */  { 23, -1, -1, G_STRING ,  0, DISABLED, UL"",         0, 2, 14, 1},
  107. /* 23 */  { 24, -1, -1, G_STRING ,  0, DISABLED, UL"",         0, 3, 14, 1},
  108. /* 24 */  { 25, -1, -1, G_STRING ,  0, DISABLED, UL"",         0, 4, 14, 1},
  109. /* 25 */  { 19, -1, -1, G_STRING ,  LASTOB, DISABLED, UL"",    0, 5, 14, 1}
  110.  
  111. };
  112.  
  113. /* About stvdi dialog object. */
  114.  
  115. OBJECT about[] = {
  116. /* 0 */  {-1,  1, 10,    G_BOX, 0, 16, 0x00021100L,           0, 0, 29, 15},
  117. /* 1 */  { 2, -1, -1, G_STRING, 0, 0, UL"Ghostscript Screen Driver", 2, 1, 25, 1},
  118. /* 2 */  { 3, -1, -1, G_STRING, 0, 0, UL"For The Atari ST",   6, 2, 16, 1},
  119. /* 3 */  { 4, -1, -1, G_STRING, 0, 0, UL"Tim Gallivan, 1992", 5, 3, 18, 1},
  120. /* 4 */  { 5, -1, -1, G_STRING, 0, 0, UL"❎n: Next Page",     5, 5, 13, 1},
  121. /* 5 */  { 6, -1, -1, G_STRING, 0, 0, UL"❎q: Quit Ghostscript",  5, 6, 20, 1},
  122. /* 6 */  { 7, -1, -1, G_STRING, 0, 0, UL"\001\002: Page Up/Down",    5, 7, 16, 1},
  123. /* 7 */  { 8, -1, -1, G_STRING, 0, 0, UL"\004\003: Page Left/Right", 5, 8, 19, 1},
  124. /* 8 */  { 9, -1, -1, G_STRING, 0, 0, UL"Scroll Bar Arrows",    6, 10, 17, 1},
  125. /* 9 */  {10, -1, -1, G_STRING, 0, 0, UL"Move to Page Edges.",  5, 11, 19, 1},
  126. /* 10 */  { 0, -1, -1, G_BUTTON, 0x62,  0, UL" OK ",           10, 13,  8, 1}
  127. };
  128.  
  129. /* General screen driver variables. */
  130.  
  131. /* lineptr is an array of pointers to the beginning of each scan line
  132.  * in the GS bitmap.
  133.  */
  134.  
  135. byte *cbase, **lineptr, *palette;
  136. uint csize, palette_size;
  137.  
  138. int wchar, hchar, wbox, hbox;
  139. int x_res, y_res, color_bits;
  140. int width, height, byte_width, word_width, raster;
  141. int plot_x, plot_y, step_dx, step_dy;
  142. int copy_width, copy_height;
  143.  
  144. /* Variables needed for GEM windows. */
  145.  
  146. char *title = " Ghostscript ";
  147. int msgbuff[8], pxy[8];
  148. int gem_handle, vdi_handle, win_handle=0, win_opened=0;
  149. int wait_event, button_state, mx, my, mb, mk, key, clicks;
  150. int hslide_pos, hslide_siz, vslide_pos, vslide_siz;
  151. int menuitem=0, scrollitem=0;
  152. int window=0, event, exit_obj;
  153. int cx, cy, cw, ch;
  154.  
  155. GRECT canvas, frame, oldframe, maxframe, full;
  156. MFDB plane_image, image, screen;
  157.  
  158. /* Global Ghostscript variables. */
  159.  
  160. gx_color_value max_rgb;
  161. ulong mem_space;
  162.  
  163. private dev_proc_open_device(stvdi_open);
  164. private dev_proc_close_device(stvdi_close);
  165. private dev_proc_output_page(stvdi_output_page);
  166. private dev_proc_print_page(stvdi_print_page);
  167. private dev_proc_map_rgb_color(stvdi_map_rgb_color);
  168. private dev_proc_map_color_rgb(stvdi_map_color_rgb);
  169.  
  170. private gx_device_procs stvdi_procs =
  171.   prn_color_procs(stvdi_open, stvdi_output_page, stvdi_close,
  172.     stvdi_map_rgb_color, stvdi_map_color_rgb);
  173.  
  174. gx_device_printer gs_stvdi_device =
  175.   prn_device(stvdi_procs, "stvdi",
  176.     WIDTH_10THS, HEIGHT_10THS,
  177.     X_DPI, Y_DPI,
  178.     0,0,0,0,            /* margins */
  179.     1, stvdi_print_page);        /* default to monochrome */
  180.  
  181. /* Open the stvdi device--get the resolution, allocate memory, etc. */
  182.  
  183. int
  184. stvdi_open(gx_device *pdev)
  185. {
  186.     const gx_device_memory *mdev;
  187.     gx_device_procs *pprocs = pdev->procs;
  188.  
  189.     byte *base;
  190.     char *env;
  191.  
  192.     int work_out[57], rgb[3], color_index[256];
  193.     int work_in[11] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2};
  194.     int i, j, ret;
  195.  
  196.     float aspect_ratio;
  197.  
  198.     /* Check the GS_WIN environment variable to decide what to
  199.      * do about windows. "Batch" means that GS can assume no
  200.      * user I/O will take place. "Interact" mode is for interactive
  201.      * use.
  202.      */
  203.  
  204.     if ((env = getenv("GS_WIN")) != NULL) {
  205.         if (!strcmp(env, "batch")) {
  206.         window = 1;        
  207.         }
  208.         else if (!strcmp(env, "interact")) {
  209.         window = 2;
  210.         }
  211.     }
  212.  
  213.     /* Call appl_init() to initialize the aes before using any aes
  214.      * functions.
  215.      */
  216.  
  217.     if (appl_init() == -1) {
  218.         eprintf("stvdi_open: appl_init() failed!\n");
  219.         return -1;
  220.     }
  221.  
  222.     /* Open a virtual workstation and get the screen resolution. */
  223.  
  224.     gem_handle = graf_handle(&wchar, &hchar, &wbox, &hbox);
  225.     vdi_handle = gem_handle;
  226.     v_opnvwk(work_in, &vdi_handle, work_out);
  227.  
  228.     if (vdi_handle == 0) {
  229.         eprintf("stvdi_open: Could not open virtual screen workstation");
  230.         exit(-1);
  231.     }
  232.  
  233.     x_res = work_out[0];
  234.     y_res = work_out[1];
  235.  
  236.     palette_size = 3 * work_out[13];
  237.     max_rgb = (int)(pow((float)work_out[39], .333) - .5);
  238.     aspect_ratio = (float)(work_out[3])/(float)(work_out[4]);
  239.  
  240.     /* Adjust the y resolution to compensate for the aspect ratio. */
  241.  
  242.     pdev->y_pixels_per_inch = 
  243.                (int)(aspect_ratio * pdev->y_pixels_per_inch + .5);
  244.     pdev->height = (int)(aspect_ratio * pdev->height + .5);
  245.  
  246.     /* Get the number of color planes. */
  247.  
  248.     vq_extnd(vdi_handle, 1, work_out);
  249.  
  250. #ifdef 8BIT
  251.     color_bits = 8;
  252. #else
  253.     color_bits = work_out[4];
  254. #endif
  255.  
  256.     if (color_bits != 1 && color_bits != 2 &&
  257.         color_bits != 4 && color_bits != 8) {
  258.         eprintf1("stvdi_open: %d bit color is not supported.\n", color_bits);
  259.         return -1;
  260.     }
  261.  
  262.     /* Get an appropriate memory device. For the moment, this must
  263.      * be an 8-bit device for color images.
  264.      */
  265.  
  266.     if ((mdev = gdev_mem_device_for_bits(color_bits > 1 ? 8 : 1)) == 0)
  267.         return_error(gs_error_rangecheck);
  268.  
  269.     width = pmemdev->width;
  270.     height = pmemdev->height;
  271.  
  272.     byte_width = (width + 7) >> 3;
  273.     word_width = (byte_width + 1) >> 1;
  274.  
  275.     /* Fill the color_info structure. */
  276.  
  277.     if (color_bits > 1) {
  278.         int psize = palette_size/3;
  279.  
  280.         /* Fill the array color_index. The value of color_index[i]
  281.          * will be the vdi color_index which corresponds to the
  282.          * ith hardware color register.
  283.          */
  284.  
  285. #ifndef 8BIT
  286.         reg_to_index(color_index, color_bits, psize);
  287. #endif
  288.         /* Fill the color_info structure. */
  289.  
  290.         ppdev->color_info.num_components = mdev->color_info.num_components;
  291.         ppdev->color_info.depth       = mdev->color_info.depth;
  292.         ppdev->color_info.max_gray    = color_bits >= 8 ? 255 : 1;
  293.         ppdev->color_info.max_rgb     = max_rgb;
  294.         ppdev->color_info.dither_gray = color_bits >= 8 ? 5 : 2;
  295.         ppdev->color_info.dither_rgb  = color_bits >= 8 ? 5 : 2;
  296.     }
  297.  
  298.     memset(ppdev->skip, 0, sizeof(ppdev->skip));
  299.     ppdev->orig_procs = pprocs;
  300.     ppdev->page_count = 0;
  301.     ppdev->file = ppdev->ccfile = ppdev->cbfile = NULL;
  302.     mem_space = gdev_mem_bitmap_size(pmemdev);
  303.  
  304.     if (color_bits > 1) {
  305.         csize = (uint)(2 * word_width * height * color_bits);
  306.         mem_space = MAX(mem_space, csize);
  307.     }
  308.  
  309.     /* Base points to a buffer that GS uses to construct the image. */
  310.  
  311.     if ( mem_space != (uint)mem_space   ||    /* too big to allocate */
  312.        (base = (byte *)gs_malloc((uint)mem_space, 1, "printer buffer"))
  313.         == 0    /* can't allocate */
  314.        ) {
  315.         eprintf("stvdi_open: Malloc for printer buffer failed.\n");
  316.         return_error(gs_error_VMerror);
  317.     }
  318.  
  319.     /* Cbase points to a buffer that holds the standard GEM
  320.      * color plane image.
  321.      */
  322.  
  323.     if (color_bits > 1) {
  324.         if ((cbase = (byte *)gs_malloc(csize, 1, "color buffer")) == 0) {
  325.         eprintf("stvdi_open: Malloc for color buffer failed.\n");
  326.         return_error(gs_error_VMerror);
  327.         }
  328.     }
  329.  
  330.        /* Render entirely in memory. */
  331.  
  332.     ppdev->buffer_space = 0;
  333.     ppdev->ccfile = NULL;
  334.     ppdev->cbfile = NULL;
  335.     pmemdev->base = base;
  336.     ppdev->mod_procs = *mdev->procs;
  337.  
  338.     /* Synthesize the procedure vector. */
  339.     /* Rendering operations come from the memory device, */
  340.     /* non-rendering come from the printer device. */
  341.  
  342.     pdev->procs = &ppdev->mod_procs;
  343. #define copy_proc(p) ppdev->mod_procs.p = pprocs->p
  344.     copy_proc(get_initial_matrix);
  345.     copy_proc(output_page);
  346.     copy_proc(close_device);
  347.     copy_proc(map_rgb_color);
  348.     copy_proc(map_color_rgb);
  349.     copy_proc(get_props);
  350.     copy_proc(put_props);
  351. #undef copy_proc
  352.  
  353.     /* Initialize the memory device. */
  354.  
  355.     if ((ret = (*pdev->procs->open_device)(pdev)) != 0) {
  356.         return ret;
  357.     }
  358.  
  359.     raster = pmemdev->raster;
  360.  
  361.     if (color_bits > 1) {
  362.  
  363.         /* Set up the palette. */
  364.  
  365.         pmemdev->palette_size = palette_size;
  366.  
  367.         if ((palette = (byte *)gs_malloc((uint)palette_size, 1, "palette"))
  368.         == NULL) {
  369.         eprintf("stvdi_open: No memory for color palette!\n");
  370.         return_error(gs_error_VMerror);
  371.         }
  372.  
  373. #ifdef 8BIT
  374.         palette[0] = 0;
  375.         palette[1] = 0;
  376.         palette[2] = 0;
  377.  
  378.         for (i=3; i<palette_size; i++) {
  379.         palette[i] = 1;
  380.         }
  381. #else
  382.         for (i=0, j=0; j<palette_size; i++, j+=3) {
  383.         vq_color(vdi_handle, color_index[i], 0, rgb);
  384.         palette[j]   = (max_rgb * rgb[0])/937;
  385.         palette[j+1] = (max_rgb * rgb[1])/937;
  386.         palette[j+2] = (max_rgb * rgb[2])/937;
  387.         }
  388. #endif
  389.         pmemdev->palette = palette;
  390.  
  391.     }
  392.  
  393.     /* Window initialization. */
  394.  
  395.     if (window) {
  396.         wind_get(0, WF_WORKXYWH, &full.g_x, &full.g_y,
  397.                      &full.g_w, &full.g_h);
  398.  
  399.         win_handle = wind_create(W_FEATURES, full.g_x, full.g_y,
  400.                          full.g_w, full.g_h);
  401.         if (win_handle == -1) {
  402.         form_alert(1,
  403.         "[3][Fatal Error !|Window not available.][Abort]");
  404.         return -1;
  405.         }
  406.  
  407.         /* Fix object sizes for current resolution. */
  408.  
  409.         objc_fix(menu);
  410.         objc_fix(about);
  411.  
  412.         wind_set(win_handle, WF_NAME, title, title, 0, 0);
  413.  
  414.         wind_get(win_handle, WF_WORKXYWH, &canvas.g_x, &canvas.g_y,
  415.                           &canvas.g_w, &canvas.g_h);
  416.  
  417.         wind_calc(0, W_FEATURES, canvas.g_x, canvas.g_y, width, height,
  418.                     &maxframe.g_x, &maxframe.g_y,
  419.                     &maxframe.g_w, &maxframe.g_h);
  420.  
  421.     }
  422.  
  423.     /* Set up the MFDBs for the images and the screen. */
  424.  
  425.     screen.fd_addr   = (long)NULL;
  426.  
  427.     image.fd_addr    = (long)base;
  428.     image.fd_w       = (color_bits > 1) ? 16 * word_width : 8 * raster;
  429.     image.fd_h       = height;
  430.     image.fd_wdwidth = image.fd_w/16;
  431.     image.fd_stand   = 0;
  432.     image.fd_nplanes = color_bits;
  433.  
  434.     if (color_bits > 1) {
  435.         plane_image.fd_addr    = (long)cbase;
  436.         plane_image.fd_w       = 16 * word_width;
  437.         plane_image.fd_h       = height;
  438.         plane_image.fd_wdwidth = image.fd_w/16;
  439.         plane_image.fd_stand   = 1;
  440.         plane_image.fd_nplanes = color_bits;
  441.     }
  442.  
  443.     return 0;
  444. }
  445.  
  446. /* Close the stvdi device--free memory, close workstations, etc. */
  447. int
  448. stvdi_close(gx_device *pdev)
  449. {
  450.     /* Free the memory device bitmap */
  451.  
  452.     gs_free((char *)pmemdev->base, (uint)gdev_mem_bitmap_size(pmemdev),
  453.         1, "printer buffer");
  454.  
  455.     /* Free the memory for the color image buffer and palette. */
  456.  
  457.     if (color_bits > 1) {
  458.         gs_free((char *)cbase, csize, 1, "color buffer");
  459.         gs_free((char *)palette, palette_size, 1, "palette");
  460.     }
  461.  
  462.     /* Free the resources used by the aes. */
  463.  
  464.     menu_bar(menu, 0);
  465.     graf_mouse(ARROW, 0L);
  466.  
  467.     if (window) {
  468.         wind_delete(win_handle);
  469.     }
  470.  
  471.     v_clsvwk(vdi_handle);
  472.     if (appl_exit() == 0) {
  473.         eprintf("stvdi_close: appl_exit() failed!\n");
  474.         return -1;
  475.     }
  476.  
  477.     pdev->procs = ppdev->orig_procs;
  478.  
  479.     return 0;
  480. }
  481.  
  482. int
  483. stvdi_output_page(gx_device *pdev, int num_copies, int flush)
  484. {    int code;
  485.  
  486.     ppdev->page_count++;
  487.  
  488.     /* print the accumulated page description */
  489.     code = (*ppdev->print_page)(ppdev, ppdev->file);
  490.     if ( code < 0 ) return code;
  491.  
  492.     return 0;
  493. }
  494.  
  495. /* Print the bitmap for the current page to the screen. */
  496.  
  497. private int
  498. stvdi_print_page(gx_device_printer *pdev, FILE *dummy)
  499. {
  500.     byte *base;
  501.  
  502.     int count, show_end, pad;
  503.  
  504.     long ch;
  505.  
  506.     /* Switch to graphics mode / clear the screen. */
  507.  
  508.     switch (window) {
  509.  
  510.     case 0:
  511.     case 2:
  512.         v_exit_cur(vdi_handle);
  513.         break;
  514.  
  515.     default:
  516.         break;
  517.  
  518.     }
  519.  
  520.     /* Open a window if requested */
  521.  
  522.     if (window && !win_opened) {
  523.  
  524.         restore_bg();
  525.         graf_mouse(M_OFF, 0L );
  526.  
  527.         menu_bar(menu, 1);
  528.  
  529.         wind_open(win_handle, full.g_x, full.g_y,
  530.                     MIN(maxframe.g_w, full.g_w),
  531.                     MIN(maxframe.g_h, full.g_h));
  532.  
  533.         wind_get(win_handle, WF_CURRXYWH, &oldframe.g_x, &oldframe.g_y,
  534.                           &oldframe.g_w, &oldframe.g_h);
  535.  
  536.         wind_get(win_handle, WF_WORKXYWH, &canvas.g_x, &canvas.g_y,
  537.                           &canvas.g_w, &canvas.g_h);
  538.  
  539.         clear_win(&canvas);
  540.         win_opened = 1;
  541.  
  542.         graf_mouse(BUSY_BEE, 0L);
  543.         graf_mouse(M_ON, 0L);
  544.  
  545.     } else {
  546.         copy_width  = MIN(x_res, width-1);    /* in pixels */
  547.         copy_height = MIN(y_res, height-1);    /* in pixels */
  548.         step_dx = .9 * copy_width;
  549.         step_dy = .9 * copy_height;
  550.     }
  551.  
  552.     show_end = 0;
  553.     pad = 8 * byte_width - width; /* pad bits at end of scan line */
  554.  
  555.     plot_x = 0;
  556.     plot_y = 0;
  557.  
  558.     lineptr = pmemdev->line_ptrs;
  559.     base = *lineptr;
  560.  
  561.     /* Find the first line containing nonzero bits. */
  562.  
  563.     while (plot_y < height) {
  564.         /* Search the scanline for a nonzero bit. */
  565.  
  566.         for (count=0; (count < byte_width)
  567.                  && (base[count] == 0); ++count) ;
  568.  
  569.         if (count >= byte_width) {    /* Empty line, continue. */
  570.         plot_y++;
  571.         base = lineptr[plot_y];
  572.         }
  573.         else if ((count==byte_width-1) && (base[count]>>pad == 0)) {
  574.         plot_y++;    /* nonzero bits in padding, continue */
  575.         base = lineptr[plot_y];
  576.         }
  577.         else {        /* Nonzero bits found, break loop. */
  578.         plot_y--;
  579.         break;
  580.         }
  581.     }
  582.  
  583.     if (plot_y < 0)
  584.         plot_y = 0;
  585.  
  586.     if (plot_y >= height - copy_height)
  587.         plot_y = (height - 1) - copy_height;
  588.  
  589.     /* Zero the memory to hold the plane image, convert the packed
  590.      * image to planes, then convert the plane image to the final
  591.      * screen format.
  592.      */
  593.  
  594.     if (color_bits > 1) {
  595.         memset(cbase, 0, csize);
  596.         stvdi_pack_to_plane(pdev);
  597.         vr_trnfm(vdi_handle, &plane_image, &image);
  598.     }
  599.  
  600. #ifdef 8BIT
  601.     getchar(); return 0;
  602. #endif
  603.  
  604.     /* Copy the appropriate portion of the image to the screen. */
  605.  
  606.     if (window) {
  607.         wait_event = MU_MESAG | MU_KEYBD;
  608.         button_state = 1;
  609.         update_scroll();
  610.     }
  611.  
  612.     while (!show_end && window) {
  613.  
  614.         step_dx = .9 * canvas.g_w;
  615.         step_dy = .9 * canvas.g_h;
  616.  
  617.         if (menuitem) {        /* fake menu events for hot keys */
  618.         event = MU_MESAG;
  619.         msgbuff[0] = MN_SELECTED;
  620.         msgbuff[4] = menuitem;
  621.         menuitem = 0;
  622.         }
  623.         else if (scrollitem) {
  624.         event = MU_MESAG;
  625.         msgbuff[0] = WM_ARROWED;
  626.         msgbuff[4] = scrollitem - 1;
  627.         scrollitem = 0;
  628.         }
  629.         else {
  630.         event = evnt_multi(wait_event, 2, 2, button_state,
  631.             1, mx, my, 1, 1, 0, 0, 0, 0, 0,
  632.             msgbuff, 0L, &mx, &my, &mb, &mk,
  633.             &key, &clicks);
  634.         }
  635.  
  636.         if (event & MU_KEYBD) {        /* hot keys */
  637.  
  638.         switch (key) {
  639.  
  640.         case 0x3100:            /* alt-n */
  641.             menuitem = NEXT;
  642.             break;
  643.  
  644.         case 0x1000:            /* alt-q */
  645.             menuitem = QUIT;
  646.             break;
  647.  
  648.         case 0x4800:            /* up arrow */
  649.             scrollitem = WA_UPPAGE + 1;
  650.             break;
  651.  
  652.         case 0x5000:            /* down arrow */
  653.             scrollitem = WA_DNPAGE + 1;
  654.             break;
  655.  
  656.         case 0x4b00:            /* left arrow */
  657.             scrollitem = WA_LFPAGE + 1;
  658.             break;
  659.  
  660.         case 0x4d00:            /* right arrow */
  661.             scrollitem = WA_RTPAGE + 1;
  662.             break;
  663.  
  664.         }
  665.  
  666.         }
  667.  
  668.         if (event & MU_MESAG) {
  669.  
  670.             switch (msgbuff[0]) {
  671.  
  672.             case MN_SELECTED:
  673.  
  674.             if (msgbuff[3] != -1) {
  675.             menu_tnormal(menu, msgbuff[3], 1);
  676.             }
  677.  
  678.             switch (msgbuff[4]) {
  679.  
  680.             case ABOUT:
  681.             exit_obj = dialog(about);
  682.             break;
  683.  
  684.             case NEXT:
  685.             wind_close(win_handle);
  686.             win_opened = 0;
  687.             graf_mouse(BUSY_BEE, 0L);
  688.             if (window == 2) {
  689.                 v_enter_cur(vdi_handle);
  690.             }
  691.             show_end = 1;
  692.             break;
  693.  
  694.             case QUIT:
  695.             wind_close(win_handle);
  696.             win_opened = 0;
  697.             if (window == 2) {
  698.                 v_enter_cur(vdi_handle);
  699.             }
  700.             stvdi_close((gx_device *)pdev);
  701.             exit(0);
  702.  
  703.             }
  704.  
  705.             break;
  706.  
  707.             case WM_REDRAW:
  708.             stvdi_win_redraw(0);
  709.             break;
  710.  
  711.             case WM_ARROWED:
  712.  
  713.             switch (msgbuff[4]) {
  714.  
  715.             case WA_UPLINE:    /* top of page */
  716.             plot_y = 0;
  717.             break;
  718.  
  719.             case WA_DNLINE:    /* bottom of page */
  720.             plot_y = (height-1) - canvas.g_h;
  721.             break;
  722.  
  723.             case WA_LFLINE:
  724.             plot_x = 0;
  725.             break;
  726.  
  727.             case WA_RTLINE:
  728.             plot_x = (width-1) - canvas.g_w;
  729.             break;
  730.  
  731.             case WA_UPPAGE:
  732.             plot_y = MAX(plot_y - step_dy, 0);
  733.             break;
  734.  
  735.             case WA_DNPAGE:
  736.             plot_y = plot_y + step_dy;
  737.             break;
  738.  
  739.             case WA_LFPAGE:
  740.             plot_x = MAX(plot_x - step_dx, 0);
  741.             break;
  742.  
  743.             case WA_RTPAGE:
  744.             plot_x = plot_x + step_dx;
  745.             break;
  746.  
  747.  
  748.             }
  749.             update_scroll();
  750.             stvdi_win_redraw(1);
  751.             break;
  752.  
  753.         case WM_HSLID:
  754.             plot_x = (width - canvas.g_w) * msgbuff[4]/1000;
  755.             update_scroll();
  756.             stvdi_win_redraw(1);
  757.             break;
  758.  
  759.         case WM_VSLID:
  760.             plot_y = (height - canvas.g_h) * msgbuff[4]/1000;
  761.             update_scroll();
  762.             stvdi_win_redraw(1);
  763.             break;
  764.  
  765.             case WM_TOPPED:
  766.             wind_set(win_handle, WF_TOP, 0, 0, 0, 0);
  767.             break;
  768.  
  769.             case WM_CLOSED:
  770.             wind_close(win_handle);
  771.             win_opened = 0;
  772.             graf_mouse(BUSY_BEE, 0L);
  773.             if (window == 2) {
  774.             v_enter_cur(vdi_handle);
  775.             }
  776.             show_end = 1;
  777.             break;
  778.  
  779.             case WM_FULLED:
  780.             wind_get(win_handle, WF_CURRXYWH,
  781.                 &frame.g_x, &frame.g_y,
  782.                 &frame.g_w, &frame.g_h);
  783.  
  784.             if (frame.g_x == full.g_x &&
  785.             frame.g_y == full.g_y &&
  786.                 frame.g_w == MIN(maxframe.g_w, full.g_w) &&
  787.             frame.g_h == MIN(maxframe.g_h, full.g_h)) {
  788.  
  789.             wind_set(win_handle, WF_CURRXYWH,
  790.                 oldframe.g_x, oldframe.g_y,
  791.                 oldframe.g_w, oldframe.g_h);
  792.  
  793.             wind_get(win_handle, WF_WORKXYWH,
  794.                 &canvas.g_x, &canvas.g_y,
  795.                 &canvas.g_w, &canvas.g_h);
  796.  
  797.             }
  798.             else {
  799.             oldframe.g_x = frame.g_x;
  800.             oldframe.g_y = frame.g_y;
  801.             oldframe.g_w = frame.g_w;
  802.             oldframe.g_h = frame.g_h;
  803.  
  804.             wind_set(win_handle, WF_CURRXYWH,
  805.                 full.g_x, full.g_y,
  806.                 MIN(maxframe.g_w, full.g_w),
  807.                 MIN(maxframe.g_h, full.g_h));
  808.  
  809.             wind_get(win_handle, WF_WORKXYWH,
  810.                 &canvas.g_x, &canvas.g_y,
  811.                 &canvas.g_w, &canvas.g_h);
  812.  
  813.             }
  814.  
  815.             update_scroll();
  816.             break;
  817.  
  818.             case WM_MOVED:
  819.             wind_set(win_handle, WF_CURRXYWH, msgbuff[4], msgbuff[5],
  820.                 MIN(maxframe.g_w, msgbuff[6]),
  821.                 MIN(maxframe.g_h, msgbuff[7]));
  822.  
  823.             wind_get(win_handle, WF_WORKXYWH,
  824.                 &canvas.g_x, &canvas.g_y,
  825.                 &canvas.g_w, &canvas.g_h);
  826.             break;
  827.  
  828.             case WM_SIZED:
  829.             wind_set(win_handle, WF_CURRXYWH, msgbuff[4], msgbuff[5],
  830.                 MIN(maxframe.g_w, msgbuff[6]),
  831.                 MIN(maxframe.g_h, msgbuff[7]));
  832.  
  833.             wind_get(win_handle, WF_WORKXYWH,
  834.                 &canvas.g_x, &canvas.g_y,
  835.                 &canvas.g_w, &canvas.g_h);
  836.  
  837.             update_scroll();
  838.             break;
  839.  
  840.         }
  841.  
  842.         }
  843.  
  844.     }
  845.  
  846.     while (!show_end && !window) {
  847.  
  848.         pxy[0] = plot_x;
  849.         pxy[1] = plot_y;
  850.         pxy[2] = pxy[0] + copy_width;
  851.         pxy[3] = pxy[1] + copy_height;
  852.         pxy[4] = 0;
  853.         pxy[5] = 0;
  854.         pxy[6] = pxy[4] + copy_width;
  855.         pxy[7] = pxy[5] + copy_height;
  856.  
  857.         graf_mouse(M_OFF, 0L );
  858.         vs_clip(vdi_handle, 1, &pxy[4]);
  859.     /*  wind_update(BEG_UPDATE);    /* lock the screen */
  860.  
  861.         vro_cpyfm(vdi_handle, 3, pxy, &image, &screen);
  862.  
  863.     /*  wind_update(END_UPDATE);    /* release screen */
  864.         vs_clip(vdi_handle, 0, &pxy[4]);
  865.         graf_mouse(ARROW, 0L );
  866.         graf_mouse(M_ON, 0L );
  867.  
  868.         /* Accept keyboard commands to manipulate the screen image. */
  869.  
  870.         ch = (Bconin(2) >> 16) & 255;    /* Get key scancode */
  871.         
  872.         switch(ch) {
  873.  
  874.         case 16:            /* Q */
  875.         show_end = 1;
  876.         break;
  877.  
  878.         case 71:            /* Clr/Home */
  879.         step_dx /= 2; step_dy /= 2;
  880.         if (step_dx < 2) step_dx = 1;
  881.         if (step_dy < 2) step_dy = 1;
  882.         break;
  883.  
  884.         case 72:            /* Up cursor */
  885.         plot_y = MAX(plot_y - step_dy, 0);
  886.         break;
  887.  
  888.         case 75:            /* Left cursor */
  889.         plot_x = MAX(plot_x - step_dx, 0);
  890.         break;
  891.  
  892.         case 77:            /* Right cursor */
  893.         plot_x = plot_x + step_dx;
  894.         if (plot_x >= width - copy_width)
  895.             plot_x = (width - 1) - copy_width;
  896.         if (plot_x < 0) plot_x = 0;
  897.         break;
  898.  
  899.         case 80:            /* Down cursor */
  900.         plot_y = plot_y + step_dy;
  901.         if (plot_y >= height - copy_height)
  902.             plot_y = (height - 1) - copy_height;
  903.         if (plot_y < 0) plot_y = 0;
  904.         break;
  905.  
  906.         case 82:            /* Insert */
  907.         step_dx *= 2; step_dy *= 2;
  908.         if (step_dx > copy_width)  step_dx = copy_width;
  909.         if (step_dy > copy_height) step_dy = copy_height;
  910.         break;
  911.  
  912.         case 97:            /* Undo */
  913.         plot_x = 0;
  914.         plot_y = 0;
  915.         break;
  916.  
  917.         case 98:            /* Help */
  918.         stvdi_DisplayHelp();
  919.         Bconin(2);
  920.         stvdi_clear_screen(0);
  921.         break;
  922.             
  923.         }
  924.  
  925.     }
  926.  
  927.     switch (window) {
  928.  
  929.     case 0:
  930.     case 2:
  931.         v_enter_cur(vdi_handle);
  932.         break;
  933.  
  934.     default:
  935.         break;
  936.  
  937.     }
  938.  
  939.     return (0);
  940.  
  941. }
  942.  
  943. int stvdi_win_redraw(int flag)
  944. {
  945.     GRECT redraw, rect;
  946.  
  947.     if (flag) {
  948.     redraw.g_x = canvas.g_x;
  949.     redraw.g_y = canvas.g_y;
  950.     redraw.g_w = canvas.g_w;
  951.     redraw.g_h = canvas.g_h;
  952.     }
  953.     else {
  954.     redraw.g_x = msgbuff[4];
  955.     redraw.g_y = msgbuff[5];
  956.     redraw.g_w = msgbuff[6];
  957.     redraw.g_h = msgbuff[7];
  958.     }
  959.  
  960.     if (plot_x >= width - canvas.g_w)
  961.     plot_x = (width - 1) - canvas.g_w;
  962.     if (plot_x < 0) plot_x = 0;
  963.  
  964.     if (plot_y >= height - canvas.g_h)
  965.     plot_y = (height - 1) - canvas.g_h;
  966.     if (plot_y < 0) plot_y = 0;
  967.  
  968.     graf_mouse(M_OFF, 0L );
  969. /*  wind_update(BEG_UPDATE);    /* lock the screen */
  970.  
  971.     wind_get(win_handle, WF_FIRSTXYWH, &rect.g_x, &rect.g_y,
  972.                        &rect.g_w, &rect.g_h);
  973.  
  974.     while (rect.g_w && rect.g_h) {
  975.     if (intersect(&redraw, &rect)) {
  976.         if (intersect(&canvas, &rect)) {
  977.         
  978.         pxy[0] = plot_x + (rect.g_x - canvas.g_x);
  979.         pxy[1] = plot_y + (rect.g_y - canvas.g_y);
  980.         pxy[2] = pxy[0] + rect.g_w - 1;
  981.         pxy[3] = pxy[1] + rect.g_h - 1;
  982.  
  983.         pxy[4] = rect.g_x;
  984.         pxy[5] = rect.g_y;
  985.         pxy[6] = pxy[4] + rect.g_w - 1;
  986.         pxy[7] = pxy[5] + rect.g_h - 1;
  987.  
  988.         vro_cpyfm(vdi_handle, 3, pxy, &image, &screen);
  989.         }
  990.     }
  991.  
  992.     wind_get(win_handle, WF_NEXTXYWH, &rect.g_x, &rect.g_y,
  993.                       &rect.g_w, &rect.g_h);
  994.     }
  995.  
  996.  
  997. /*  wind_update(END_UPDATE);    /* release screen */
  998.  
  999.     graf_mouse(ARROW, 0L );
  1000.     graf_mouse(M_ON, 0L );
  1001.  
  1002. }
  1003.  
  1004. int update_scroll()
  1005. {
  1006.     if (width != canvas.g_w) {
  1007.     hslide_pos = 1000 * plot_x/(width - canvas.g_w);
  1008.     }
  1009.     else {
  1010.     hslide_pos = 0;
  1011.     }
  1012.  
  1013.     if (height != canvas.g_h) {
  1014.     vslide_pos = 1000 * plot_y/(height - canvas.g_h);
  1015.     }
  1016.     else {
  1017.     vslide_pos = 0;
  1018.     }
  1019.  
  1020.     hslide_siz = 1000 * canvas.g_w/width;
  1021.     vslide_siz = 1000 * canvas.g_h/height;
  1022.  
  1023.     wind_set(win_handle, WF_HSLIDE, hslide_pos);
  1024.     wind_set(win_handle, WF_VSLIDE, vslide_pos);
  1025.     wind_set(win_handle, WF_HSLSIZE, hslide_siz);
  1026.     wind_set(win_handle, WF_VSLSIZE, vslide_siz);
  1027. }
  1028.  
  1029. int stvdi_DisplayHelp()
  1030. {
  1031.     dprintf2("%c%c Help for GhostScript Screen Driver\n", 27, 'E');
  1032.     dprintf(" Original Code by Hauke Hess.\n\n");
  1033.     dprintf(" Q:            Quit this page (to next page or GS prompt).\n");
  1034.     dprintf(" Cursor Keys:  Scroll screen in direction of cursor.\n");
  1035.     dprintf(" Help:         Display help screen.\n");
  1036.     dprintf(" Undo:         Move to upper-left corner of page.\n");
  1037.     dprintf(" Insert:       Multiply scroll incrememt by 2.\n");
  1038.     dprintf(" Clr/Home:     Divide scroll increment by 2.\n");
  1039.     dprintf("\n Command line option -r<XDPI>x<YDPI> sets resolution.\n");
  1040.  
  1041. #if 0
  1042.     dprintf("\n Helpseite des GhostScript Previewers no(c)\n");
  1043.     dprintf(" Hauke Heß 1991\n");
  1044.     dprintf(" Cursortasten: bewegen in entsprechender Richtung\n");
  1045.     dprintf(" Undo:         Zurück nach links oben auf der Seite\n");
  1046.     dprintf(" Insert:       Schrittweiter vergrößern\n");
  1047.     dprintf(" Clr/Home:     Schrittweite verkleinern\n");
  1048.     dprintf("\n Kommandozeilenparameter -r<XDPI>x<YDPI> setzt die Auflösung\n");
  1049. #endif
  1050.  
  1051.     dprintf("\n >> Hit any key to continue. <<");
  1052.  
  1053.     return(0);
  1054. }
  1055.  
  1056. int
  1057. stvdi_clear_screen(int cursor)
  1058. {
  1059.     if (cursor) {
  1060.         v_enter_cur(vdi_handle);
  1061.     }
  1062.     else {
  1063.         v_exit_cur(vdi_handle);
  1064.     }
  1065. }
  1066.  
  1067.  
  1068. /* Map a r-g-b color to a color index. */
  1069. /* This requires searching the palette. */
  1070.  
  1071. gx_color_index
  1072. stvdi_map_rgb_color(gx_device *pdev, gx_color_value r, gx_color_value g,
  1073.   gx_color_value b) {
  1074.     byte br = gx_color_value_to_byte(r);
  1075.     byte bg = gx_color_value_to_byte(g);
  1076.     byte bb = gx_color_value_to_byte(b);
  1077.     register byte *pptr = pmemdev->palette;
  1078.     int cnt = pmemdev->palette_size;
  1079.     byte *which;
  1080.     int best = 256*3;
  1081.  
  1082.     if (color_bits == 1) {        /* monochrome */
  1083.       return ((r | g | b) > gx_max_color_value / 2 ?
  1084.             (gx_color_index)0 : (gx_color_index)1);
  1085.     }
  1086.  
  1087.     br = (br * max_rgb)/255;
  1088.     bg = (bg * max_rgb)/255;
  1089.     bb = (bb * max_rgb)/255;
  1090.  
  1091.     while ( cnt-- > 0 )
  1092.        {    register int diff = *pptr - br;
  1093.         if ( diff < 0 ) diff = -diff;
  1094.         if ( diff < best )    /* quick rejection */
  1095.            {    int dg = pptr[1] - bg;
  1096.             if ( dg < 0 ) dg = -dg;
  1097.             if ( (diff += dg) < best )    /* quick rejection */
  1098.                {    int db = pptr[2] - bb;
  1099.                 if ( db < 0 ) db = -db;
  1100.                 if ( (diff += db) < best )
  1101.                     which = pptr, best = diff;
  1102.                }
  1103.            }
  1104.         pptr += 3;
  1105.        }
  1106.     return (gx_color_index)((which - pmemdev->palette) / 3);
  1107. }
  1108.  
  1109. /* Map a color index to a r-g-b color. */
  1110. int
  1111. stvdi_map_color_rgb(gx_device *pdev, gx_color_index color,
  1112.   gx_color_value prgb[3])
  1113. {
  1114.     byte *pptr;
  1115.  
  1116.     if (color_bits == 1) {        /* monochrome */
  1117.       return gdev_prn_map_color_rgb(pdev, color, prgb);
  1118.     }
  1119.  
  1120.     pptr = pmemdev->palette + (int)color * 3;
  1121.     prgb[0] = gx_color_value_from_byte(pptr[0]);
  1122.     prgb[1] = gx_color_value_from_byte(pptr[1]);
  1123.     prgb[2] = gx_color_value_from_byte(pptr[2]);
  1124.     return 0;
  1125. }
  1126.  
  1127. /* Copy an image from Ghostscript's format to standard color planes. */
  1128.  
  1129. int
  1130. stvdi_pack_to_plane(gx_device *pdev)
  1131. {
  1132.     byte *base, *plane1, *plane2, *plane3, *plane4,
  1133.             *plane5, *plane6, *plane7, *plane8;
  1134.  
  1135.     byte *next_pl1, *next_pl2, *next_pl3, *next_pl4,
  1136.          *next_pl5, *next_pl6, *next_pl7, *next_pl8;
  1137.  
  1138.     int pixel, line, plane_size;
  1139.  
  1140.     plane_size = 2 * word_width * height;
  1141.  
  1142.     switch (color_bits) {
  1143.  
  1144.     case 2:        /* Two bit color. */
  1145.  
  1146.         next_pl1 = cbase;
  1147.         next_pl2 = cbase + plane_size;
  1148.  
  1149.         for (line=0; line < height; line++) {
  1150.         base = lineptr[line];
  1151.  
  1152.         plane1 = next_pl1;
  1153.         plane2 = next_pl2;
  1154.  
  1155.         next_pl1 += 2 * word_width;
  1156.         next_pl2 += 2 * word_width;
  1157.    
  1158.         for (pixel=0; pixel < width; plane1++, plane2++, pixel+=8) {
  1159.  
  1160.             if (*base & 0x01) *plane1 |= 0x80;
  1161.             if (*base & 0x02) *plane2 |= 0x80;
  1162.             ++base;
  1163.  
  1164.             if (*base & 0x01) *plane1 |= 0x40;
  1165.             if (*base & 0x02) *plane2 |= 0x40;
  1166.             ++base;
  1167.  
  1168.             if (*base & 0x01) *plane1 |= 0x20;
  1169.             if (*base & 0x02) *plane2 |= 0x20;
  1170.             ++base;
  1171.  
  1172.             if (*base & 0x01) *plane1 |= 0x10;
  1173.             if (*base & 0x02) *plane2 |= 0x10;
  1174.             ++base;
  1175.  
  1176.             if (*base & 0x01) *plane1 |= 0x08;
  1177.             if (*base & 0x02) *plane2 |= 0x08;
  1178.             ++base;
  1179.  
  1180.             if (*base & 0x01) *plane1 |= 0x04;
  1181.             if (*base & 0x02) *plane2 |= 0x04;
  1182.             ++base;
  1183.  
  1184.             if (*base & 0x01) *plane1 |= 0x02;
  1185.             if (*base & 0x02) *plane2 |= 0x02;
  1186.             ++base;
  1187.  
  1188.             if (*base & 0x01) *plane1 |= 0x01;
  1189.             if (*base & 0x02) *plane2 |= 0x01;
  1190.             ++base;
  1191.  
  1192.         }
  1193.  
  1194.         }
  1195.  
  1196.         break;
  1197.  
  1198.     case 4:        /* Four bit color. */
  1199.  
  1200.         next_pl1 = cbase;
  1201.         next_pl2 = cbase + plane_size;
  1202.         next_pl3 = cbase + 2 * plane_size;
  1203.         next_pl4 = cbase + 3 * plane_size;
  1204.  
  1205.         for (line=0; line < height; line++) {
  1206.         base = lineptr[line];
  1207.  
  1208.         plane1 = next_pl1;
  1209.         plane2 = next_pl2;
  1210.         plane3 = next_pl3;
  1211.         plane4 = next_pl4;
  1212.  
  1213.         next_pl1 += 2 * word_width;
  1214.         next_pl2 += 2 * word_width;
  1215.         next_pl3 += 2 * word_width;
  1216.         next_pl4 += 2 * word_width;
  1217.  
  1218.         for (pixel=0; pixel < width; plane1++, plane2++,
  1219.                 plane3++, plane4++, pixel+=8) {
  1220.  
  1221.             if (*base & 0x01) *plane1 |= 0x80;
  1222.             if (*base & 0x02) *plane2 |= 0x80;
  1223.             if (*base & 0x04) *plane3 |= 0x80;
  1224.             if (*base & 0x08) *plane4 |= 0x80;
  1225.             ++base;
  1226.  
  1227.             if (*base & 0x01) *plane1 |= 0x40;
  1228.             if (*base & 0x02) *plane2 |= 0x40;
  1229.             if (*base & 0x04) *plane3 |= 0x40;
  1230.             if (*base & 0x08) *plane4 |= 0x40;
  1231.             ++base;
  1232.  
  1233.             if (*base & 0x01) *plane1 |= 0x20;
  1234.             if (*base & 0x02) *plane2 |= 0x20;
  1235.             if (*base & 0x04) *plane3 |= 0x20;
  1236.             if (*base & 0x08) *plane4 |= 0x20;
  1237.             ++base;
  1238.  
  1239.             if (*base & 0x01) *plane1 |= 0x10;
  1240.             if (*base & 0x02) *plane2 |= 0x10;
  1241.             if (*base & 0x04) *plane3 |= 0x10;
  1242.             if (*base & 0x08) *plane4 |= 0x10;
  1243.             ++base;
  1244.  
  1245.             if (*base & 0x01) *plane1 |= 0x08;
  1246.             if (*base & 0x02) *plane2 |= 0x08;
  1247.             if (*base & 0x04) *plane3 |= 0x08;
  1248.             if (*base & 0x08) *plane4 |= 0x08;
  1249.             ++base;
  1250.  
  1251.             if (*base & 0x01) *plane1 |= 0x04;
  1252.             if (*base & 0x02) *plane2 |= 0x04;
  1253.             if (*base & 0x04) *plane3 |= 0x04;
  1254.             if (*base & 0x08) *plane4 |= 0x04;
  1255.             ++base;
  1256.  
  1257.             if (*base & 0x01) *plane1 |= 0x02;
  1258.             if (*base & 0x02) *plane2 |= 0x02;
  1259.             if (*base & 0x04) *plane3 |= 0x02;
  1260.             if (*base & 0x08) *plane4 |= 0x02;
  1261.             ++base;
  1262.  
  1263.             if (*base & 0x01) *plane1 |= 0x01;
  1264.             if (*base & 0x02) *plane2 |= 0x01;
  1265.             if (*base & 0x04) *plane3 |= 0x01;
  1266.             if (*base & 0x08) *plane4 |= 0x01;
  1267.             ++base;
  1268.  
  1269.         }
  1270.  
  1271.         }
  1272.  
  1273.         break;
  1274.  
  1275.     case 8:        /* Eight bit color. */
  1276.  
  1277.         next_pl1 = cbase;
  1278.         next_pl2 = cbase + plane_size;
  1279.         next_pl3 = cbase + 2 * plane_size;
  1280.         next_pl4 = cbase + 3 * plane_size;
  1281.         next_pl5 = cbase + 4 * plane_size;
  1282.         next_pl6 = cbase + 5 * plane_size;
  1283.         next_pl7 = cbase + 6 * plane_size;
  1284.         next_pl8 = cbase + 7 * plane_size;
  1285.  
  1286.         for (line=0; line < height; line++) {
  1287.         base = lineptr[line];
  1288.  
  1289.         plane1 = next_pl1;
  1290.         plane2 = next_pl2;
  1291.         plane3 = next_pl3;
  1292.         plane4 = next_pl4;
  1293.         plane5 = next_pl5;
  1294.         plane6 = next_pl6;
  1295.         plane7 = next_pl7;
  1296.         plane8 = next_pl8;
  1297.  
  1298.         next_pl1 += 2 * word_width;
  1299.         next_pl2 += 2 * word_width;
  1300.         next_pl3 += 2 * word_width;
  1301.         next_pl4 += 2 * word_width;
  1302.         next_pl5 += 2 * word_width;
  1303.         next_pl6 += 2 * word_width;
  1304.         next_pl7 += 2 * word_width;
  1305.         next_pl8 += 2 * word_width;
  1306.  
  1307.         for (pixel=0; pixel < width; plane1++, plane2++,
  1308.              plane3++, plane4++, plane5++, plane6++,
  1309.              plane7++, plane8++, pixel+=8) {
  1310.  
  1311.             if (*base & 0x01) *plane1 |= 0x80;
  1312.             if (*base & 0x02) *plane2 |= 0x80;
  1313.             if (*base & 0x04) *plane3 |= 0x80;
  1314.             if (*base & 0x08) *plane4 |= 0x80;
  1315.             if (*base & 0x10) *plane5 |= 0x80;
  1316.             if (*base & 0x20) *plane6 |= 0x80;
  1317.             if (*base & 0x40) *plane7 |= 0x80;
  1318.             if (*base & 0x80) *plane8 |= 0x80;
  1319.             ++base;
  1320.  
  1321.             if (*base & 0x01) *plane1 |= 0x40;
  1322.             if (*base & 0x02) *plane2 |= 0x40;
  1323.             if (*base & 0x04) *plane3 |= 0x40;
  1324.             if (*base & 0x08) *plane4 |= 0x40;
  1325.             if (*base & 0x10) *plane5 |= 0x40;
  1326.             if (*base & 0x20) *plane6 |= 0x40;
  1327.             if (*base & 0x40) *plane7 |= 0x40;
  1328.             if (*base & 0x80) *plane8 |= 0x40;
  1329.             ++base;
  1330.  
  1331.             if (*base & 0x01) *plane1 |= 0x20;
  1332.             if (*base & 0x02) *plane2 |= 0x20;
  1333.             if (*base & 0x04) *plane3 |= 0x20;
  1334.             if (*base & 0x08) *plane4 |= 0x20;
  1335.             if (*base & 0x10) *plane5 |= 0x20;
  1336.             if (*base & 0x20) *plane6 |= 0x20;
  1337.             if (*base & 0x40) *plane7 |= 0x20;
  1338.             if (*base & 0x80) *plane8 |= 0x20;
  1339.             ++base;
  1340.  
  1341.             if (*base & 0x01) *plane1 |= 0x10;
  1342.             if (*base & 0x02) *plane2 |= 0x10;
  1343.             if (*base & 0x04) *plane3 |= 0x10;
  1344.             if (*base & 0x08) *plane4 |= 0x10;
  1345.             if (*base & 0x10) *plane5 |= 0x10;
  1346.             if (*base & 0x20) *plane6 |= 0x10;
  1347.             if (*base & 0x40) *plane7 |= 0x10;
  1348.             if (*base & 0x80) *plane8 |= 0x10;
  1349.             ++base;
  1350.  
  1351.             if (*base & 0x01) *plane1 |= 0x08;
  1352.             if (*base & 0x02) *plane2 |= 0x08;
  1353.             if (*base & 0x04) *plane3 |= 0x08;
  1354.             if (*base & 0x08) *plane4 |= 0x08;
  1355.             if (*base & 0x10) *plane5 |= 0x08;
  1356.             if (*base & 0x20) *plane6 |= 0x08;
  1357.             if (*base & 0x40) *plane7 |= 0x08;
  1358.             if (*base & 0x80) *plane8 |= 0x08;
  1359.             ++base;
  1360.  
  1361.             if (*base & 0x01) *plane1 |= 0x04;
  1362.             if (*base & 0x02) *plane2 |= 0x04;
  1363.             if (*base & 0x04) *plane3 |= 0x04;
  1364.             if (*base & 0x08) *plane4 |= 0x04;
  1365.             if (*base & 0x10) *plane5 |= 0x04;
  1366.             if (*base & 0x20) *plane6 |= 0x04;
  1367.             if (*base & 0x40) *plane7 |= 0x04;
  1368.             if (*base & 0x80) *plane8 |= 0x04;
  1369.             ++base;
  1370.  
  1371.             if (*base & 0x01) *plane1 |= 0x02;
  1372.             if (*base & 0x02) *plane2 |= 0x02;
  1373.             if (*base & 0x04) *plane3 |= 0x02;
  1374.             if (*base & 0x08) *plane4 |= 0x02;
  1375.             if (*base & 0x10) *plane5 |= 0x02;
  1376.             if (*base & 0x20) *plane6 |= 0x02;
  1377.             if (*base & 0x40) *plane7 |= 0x02;
  1378.             if (*base & 0x80) *plane8 |= 0x02;
  1379.             ++base;
  1380.  
  1381.             if (*base & 0x01) *plane1 |= 0x01;
  1382.             if (*base & 0x02) *plane2 |= 0x01;
  1383.             if (*base & 0x04) *plane3 |= 0x01;
  1384.             if (*base & 0x08) *plane4 |= 0x01;
  1385.             if (*base & 0x10) *plane5 |= 0x01;
  1386.             if (*base & 0x20) *plane6 |= 0x01;
  1387.             if (*base & 0x40) *plane7 |= 0x01;
  1388.             if (*base & 0x80) *plane8 |= 0x01;
  1389.             ++base;
  1390.  
  1391.         }
  1392.  
  1393.         }
  1394.  
  1395.         break;
  1396.  
  1397.     default:
  1398.         return -1;
  1399.  
  1400.     }
  1401.  
  1402.     return (0);
  1403. }
  1404.  
  1405. int dialog(OBJECT *object)
  1406. {
  1407.     int exit_but;
  1408.  
  1409.     form_center(object, &cx, &cy, &cw, &ch);
  1410.     form_dial(FMD_START, 0, 0, wchar, hchar, cx, cy, cw, ch);
  1411.     objc_draw(object, 0, 5, cx, cy, cw, ch);
  1412.  
  1413.     exit_but = form_do(object, 0);
  1414.  
  1415.     form_dial(FMD_FINISH, 0, 0, wchar, hchar, cx, cy, cw, ch);
  1416.     objc_change(&object[exit_but], 0, 0, cx, cy, cw, ch, NORMAL, 0);
  1417.  
  1418.     return exit_but;
  1419. }
  1420.  
  1421. int intersect(GRECT *rec1, GRECT *rec2)
  1422. {
  1423.     GRECT temp;
  1424.  
  1425.     temp.g_x = MAX(rec1->g_x, rec2->g_x);
  1426.     temp.g_y = MAX(rec1->g_y, rec2->g_y);
  1427.     temp.g_w = MIN(rec1->g_x + rec1->g_w, rec2->g_x + rec2->g_w);
  1428.     temp.g_h = MIN(rec1->g_y + rec1->g_h, rec2->g_y + rec2->g_h);
  1429.  
  1430.     rec2->g_x = temp.g_x;
  1431.     rec2->g_y = temp.g_y;
  1432.     rec2->g_w = temp.g_w - temp.g_x;
  1433.     rec2->g_h = temp.g_h - temp.g_y;
  1434.  
  1435.     return ((temp.g_w > temp.g_x) && (temp.g_h > temp.g_y));
  1436. }
  1437.  
  1438. /* Restore the usual desktop background. */
  1439.  
  1440. int restore_bg()
  1441. {
  1442.     puts("\033f");
  1443.     v_hide_c(vdi_handle);
  1444.     form_dial(FMD_FINISH, 0, 0, 8, 16, 0, 0, x_res, y_res);
  1445.     v_show_c(vdi_handle, 0);
  1446. }
  1447.  
  1448. /* Adjust the size of an object for the current screen resolution. */
  1449.  
  1450. int objc_fix(OBJECT *object)
  1451. {
  1452.     int i=-1;
  1453.  
  1454.     do {
  1455.     i++;
  1456.  
  1457.     if      (object[i].ob_x == 769) object[i].ob_x = full.g_y;
  1458.     else if (object[i].ob_x == 513) object[i].ob_x = full.g_y;
  1459.     else                object[i].ob_x *= wchar;
  1460.  
  1461.     if      (object[i].ob_y == 769) object[i].ob_y = full.g_y;
  1462.     else if (object[i].ob_y == 513) object[i].ob_y = full.g_y;
  1463.     else                object[i].ob_y *= hchar;
  1464.  
  1465.     if      (object[i].ob_width == 769) object[i].ob_width = full.g_y;
  1466.     else if (object[i].ob_width == 513) object[i].ob_width = full.g_y;
  1467.     else if (object[i].ob_width == 80)  object[i].ob_width = full.g_w;
  1468.     else                    object[i].ob_width *= wchar;
  1469.  
  1470.     if      (object[i].ob_height == 769) object[i].ob_height = full.g_y;
  1471.     else if (object[i].ob_height == 513) object[i].ob_height = full.g_y;
  1472.     else                     object[i].ob_height *= hchar;
  1473.  
  1474.     }
  1475.     while (!(object[i].ob_flags & LASTOB));
  1476.  
  1477. }
  1478.  
  1479. int clear_win(GRECT *area)
  1480. {
  1481.     int xy[4];
  1482.  
  1483.     xy[0] = area->g_x;
  1484.     xy[1] = area->g_y;
  1485.     xy[2] = xy[0] + area->g_w - 1;
  1486.     xy[3] = xy[1] + area->g_h - 1;
  1487.  
  1488.     vsf_interior(vdi_handle, 0);    /* set fill mode to hollow */
  1489.     vr_recfl(vdi_handle, xy);        /* clear the window */
  1490. }
  1491.  
  1492. int reg_to_index(int index_array[], int c_bits, int p_size)
  1493. {
  1494.     unsigned short *wp;
  1495.  
  1496.     int i, index, creg, xy_pos[2], xy_size[8];
  1497.  
  1498.     long tpixel[4], plane[4];
  1499.  
  1500.     MFDB temp, screen, planes;
  1501.  
  1502.     screen.fd_addr   = (long)NULL;
  1503.  
  1504.     /* Temporary storage for for 16 screen pixels. */
  1505.  
  1506.     temp.fd_addr    = (long)tpixel;
  1507.     temp.fd_w       = 16;
  1508.     temp.fd_h       = 1;
  1509.     temp.fd_wdwidth = 1;
  1510.     temp.fd_stand   = 0;
  1511.     temp.fd_nplanes = c_bits;
  1512.  
  1513.     /* 16 screen pixels in plane format. */
  1514.  
  1515.     planes.fd_addr    = (long)plane;
  1516.     planes.fd_w       = 16;
  1517.     planes.fd_h       = 1;
  1518.     planes.fd_wdwidth = 1;
  1519.     planes.fd_stand   = 0;
  1520.     planes.fd_nplanes = c_bits;
  1521.  
  1522.     /* Screen position to write pixel. */
  1523.  
  1524.     xy_pos[0] = 0;
  1525.     xy_pos[1] = 0;
  1526.  
  1527.     /* Size of screen image to copy. */
  1528.  
  1529.     xy_size[0] = 0;
  1530.     xy_size[1] = 0;
  1531.     xy_size[2] = 15;
  1532.     xy_size[3] = 0;
  1533.     xy_size[4] = xy_size[0];
  1534.     xy_size[5] = xy_size[1];
  1535.     xy_size[6] = xy_size[2];
  1536.     xy_size[7] = xy_size[3];
  1537.  
  1538.     vswr_mode(vdi_handle, 1);    /* overwrite mode    */
  1539.     vsm_type(vdi_handle, 1);    /* marker type "dot" */
  1540.  
  1541.     for (index=0; p_size--; index++) {
  1542.         wp = (short int *)plane;
  1543.  
  1544.         vsm_color(vdi_handle, index);    /* set pixel color */
  1545.         v_pmarker(vdi_handle, 1, xy_pos);    /* write pixel to screen */
  1546.  
  1547.         /* Copy pixel into temporary storage (transforming directly
  1548.          * from the screen doesn't work on my machine).
  1549.          */
  1550.  
  1551.         vro_cpyfm(vdi_handle, 3, xy_size, &screen, &temp);    
  1552.  
  1553.         /* Transform the screen image into color plane format. */
  1554.  
  1555.         vr_trnfm(vdi_handle, &temp, &planes);
  1556.  
  1557.         /* Convert the color plane information into a register number. */
  1558.  
  1559.         creg = 0;
  1560.         for (i=1; i<=c_bits; wp++, i++) {
  1561.         if (*wp & 0x8000) {
  1562.             creg += (1 << (i-1));
  1563.         }
  1564.         }
  1565.  
  1566.         index_array[creg] = index;
  1567.  
  1568.     }
  1569.  
  1570. }
  1571.