home *** CD-ROM | disk | FTP | other *** search
/ TopWare 18: Liquid / Image.iso / liquid / top1089 / rdsgen.c < prev    next >
Text File  |  1993-12-17  |  65KB  |  2,650 lines

  1. /*                                                                                                    */
  2. /*    RDSGEN.C - Random-Dot Stereogram Generator                                        */
  3. /*                                                                                                    */
  4. /*    Version 1.1B                                                                                */
  5. /*                                                                                                    */
  6. /*    Written by: Fred Feucht                                                                    */
  7. /*                                                                                                    */
  8. /*                                                                                                    */
  9. /*    This program will take a type 2 TARGA or GIF file as input and             */
  10. /*    generate a type 3 TARGA or GIF output file as an RDS.                            */
  11. /*                                                                                                    */
  12. /*    The original code comes from RDS.C by Alexander R. Enzmann, which I         */
  13. /* found    to be too inflexible.  The RDS algorithm is a modification of        */
  14. /*    the routine documented by Paul McMahon in "The Emporors New Clothes".    */
  15. /* With the additions of GIF encoding and decoding routines from TGA2GIF    */
  16. /* and POVRay respectively (authors are mentioned below).                        */
  17. /*                                                                                                    */
  18. /*    My thanks to all the previous authors whose code fragments appear         */
  19. /*    herein.  I have given credit wherever possible to original authors.        */
  20. /* To those not specifically mentioned, I am grateful as well.                    */
  21. /*                                                                                                    */
  22. /* Permission is given by the author to freely redistribute and include        */
  23. /* this code in any program as long as this credit is given where due.        */
  24. /*                                                                                                    */
  25. /* GIF and 'Graphics Interchange Format' are trademarks (tm) of                */
  26. /* Compuserve, Incorporated, an H&R Block Company.                                    */
  27. /*                                                                                                    */
  28. /***************************************************************************/
  29. /*                                                                                                    */
  30. /*    Revisions for release 1.1                                                                */
  31. /*                                                                                                    */
  32. /*                                                                                                    */
  33. /*    Additional RDS algorithms     /a switch                                                */
  34. /*                                                                                                    */
  35. /*    Random color background        /c switch                                                */
  36. /*                                                                                                    */
  37. /*    GIF background map            /m switch                                                */
  38. /*                                                                                                    */
  39. /*    Depth of field control        /f switch                                                */
  40. /*                                                                                                    */
  41. /* Printer support for EPSON LQ, LASER JET, and POSTSCRIPT (incomplete)        */
  42. /*                                                                                                    */
  43. /*                                                                                                    */
  44.  
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <stdarg.h>
  48. #include <math.h>
  49. #include <ctype.h>
  50. #include <graphics.h>
  51.  
  52. #include "rdsgen.h"
  53.  
  54. /*                            */
  55. /* Global variables    */
  56. /*                            */
  57.  
  58. static int                    stripc, density, direction, outfile, display, field;
  59. static int                    color_back, seed, algorithm, adapt, index_points;
  60. static int                    stripw, intype, point_max, map_file, scale;
  61. static long                    limit, zmax, zmin, newval, oldval, num, den;
  62. static unsigned int        xres, yres;
  63.  
  64. static unsigned int *    depths;
  65. static unsigned char *    odata;
  66.  
  67. static int                     Width, Height;
  68. static int                     curx, cury;
  69. static long                 CountDown;
  70. static int                     Pass = 0;
  71. static int                     Interlace;
  72.  
  73. static FILE *                ofile;
  74. static char *                oname;
  75.  
  76. static char *                printer;
  77. static unsigned char *    printx;
  78. static unsigned char **    printy;
  79.  
  80. static int *                same;
  81.  
  82. static int                    sep;
  83. static int                    left, right, sl, sr;
  84.  
  85.  
  86. /*                                */
  87. /* input file stuff        */
  88. /*                                */
  89.  
  90. static FILE *                ifile;                    /* input file handle                    */
  91. static char *                iname;                    /* input file name                    */
  92.  
  93. static unsigned char *    iemit_index;
  94. static unsigned char *     icmap;
  95. static unsigned int        ftype, icmlen, icmsize, ipsize, idlen;
  96. static int                    icode_size,    iout_value, iold_code, ibad_code_count;
  97.  
  98. LOCAL WORD                     icurr_size;             /* The current code size             */
  99. LOCAL WORD                     iclear;                 /* Value for a clear code             */
  100. LOCAL WORD                     iending;                /* Value for a ending code         */
  101. LOCAL WORD                     inew_codes;             /* First available code             */
  102. LOCAL WORD                     itop_slot;              /* Highest code for current size */
  103. LOCAL WORD                     islot;                  /* Last read code                     */
  104.  
  105. LOCAL WORD                     ibyte_count = 0;         /* # bytes left in block             */
  106. LOCAL WORD                     ibit_count = 0;         /* # bits left in current byte     */
  107. LOCAL UTINY                 ibyte_buff[257];        /* Current block                         */
  108. LOCAL UTINY *                ibyte_ptr;           /* Pointer to next byte in block */
  109. LOCAL UTINY                 ibyte;                      /* current input byte                 */
  110.  
  111. LOCAL UTINY *                idstack;                    /* Stack for storing pixels         */
  112. LOCAL UTINY *                isuffix;                    /* Suffix table                         */
  113. LOCAL UWORD *                iprefix;                    /* Prefix linked list                 */
  114.  
  115. /*                                    */
  116. /* background file stuff    */
  117. /*                                    */
  118.  
  119. static FILE *                bfile;                    /* input file handle                    */
  120. static char *                bname;                    /* input file name                    */
  121.  
  122. static unsigned char *    bemit_index;
  123. static int                    bcode_size,    bout_value, bold_code, bbad_code_count;
  124. static unsigned char *     bcmap;
  125. static unsigned int        bxres, byres, bcmlen, bcmsize;
  126.  
  127. LOCAL WORD                     bcurr_size;             /* The current code size             */
  128. LOCAL WORD                     bclear;                 /* Value for a clear code             */
  129. LOCAL WORD                     bending;                /* Value for a ending code         */
  130. LOCAL WORD                     bnew_codes;             /* First available code             */
  131. LOCAL WORD                     btop_slot;              /* Highest code for current size */
  132. LOCAL WORD                     bslot;                  /* Last read code                     */
  133.  
  134. LOCAL WORD                     bbyte_count = 0;         /* # bytes left in block             */
  135. LOCAL WORD                     bbit_count = 0;         /* # bits left in current byte     */
  136. LOCAL UTINY                 bbyte_buff[257];        /* Current block                         */
  137. LOCAL UTINY *                bbyte_ptr;           /* Pointer to next byte in block */
  138. LOCAL UTINY                 bbyte;                      /* current input byte                 */
  139.  
  140. LOCAL UTINY *                bdstack;                    /* Stack for storing pixels         */
  141. LOCAL UTINY *                bsuffix;                    /* Suffix table                         */
  142. LOCAL UWORD *                bprefix;                    /* Prefix linked list                 */
  143.  
  144. /*                                */
  145. /* output file stuff        */
  146. /*                                */
  147.  
  148. static unsigned char        idbuf[256];
  149.  
  150. static int n_bits;                        /* number of bits/code */
  151. static int maxbits = BITS;                /* user settable max # bits/code */
  152. static code_int maxcode;                  /* maximum code, given n_bits */
  153. static code_int maxmaxcode = (code_int)1 << BITS; /* should NEVER generate this code */
  154. static count_int htab [HSIZE];
  155. static unsigned short codetab [HSIZE];
  156.  
  157. static code_int free_ent = 0;             /* first unused entry */
  158. static int exit_stat = 0;
  159.  
  160. static int clear_flg = 0;
  161.  
  162. static int offset;
  163. static long int in_count = 1;                /* length of input */
  164. static long int out_count = 0;               /* # of codes output (for debugging) */
  165.  
  166. static int g_init_bits;
  167. static FILE *g_outfile;
  168.  
  169. static int ClearCode;
  170. static int EOFCode;
  171.  
  172. static code_int             hsize = HSIZE;     /* for dynamic table sizing */
  173. static count_int             fsize;
  174.  
  175. static unsigned long     cur_accum = 0;
  176. static int                  cur_bits = 0;
  177.  
  178. LOCAL ULONG code_mask[17] = {
  179.   0,
  180.   0x0001, 0x0003,
  181.   0x0007, 0x000F,
  182.   0x001F, 0x003F,
  183.   0x007F, 0x00FF,
  184.   0x01FF, 0x03FF,
  185.   0x07FF, 0x0FFF,
  186.   0x1FFF, 0x3FFF,
  187.   0x7FFF, 0xFFFF
  188.   };
  189.  
  190. static int red[256] = { 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x1F, 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF };
  191.  
  192. static int green[256] = { 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x1F, 0x7F, 0x1F, 0x1F, 0xFF, 0xFF, 0x1F, 0x1F, 0xFF, 0xFF };
  193.  
  194. static int blue[256] = { 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x1F, 0xFF, 0x1F, 0xFF, 0x1F, 0xFF, 0x1F, 0xFF };
  195.  
  196. const char GIFstr[] = "GIF87a";
  197.  
  198.  
  199. /*                                               */
  200. /* Main processing routine                     */
  201. /*                                               */
  202.  
  203. void main(argc, argv)
  204.  
  205. int argc;
  206. char **argv;
  207.  
  208. {
  209.     int    i, j;
  210.  
  211.     int    driver, mode, errcode;
  212.  
  213.     unsigned char * t;
  214.  
  215.  
  216.     stripc = 8;                    /* strip length = 1/8 of screen width */
  217.  
  218.    density = 50;                /* density 50 out of 100 pixels black    */
  219.  
  220.     direction = 0;                /* normal picture orientation                */ 
  221.  
  222.     outfile = 0;                /* output file is GIF format                */
  223.  
  224.     display = 0;                /* do not display output while working */
  225.  
  226.     seed = 1;                    /* random number seed                        */
  227.  
  228.     adapt = 0;                    /* no background substitution                */
  229.  
  230.     index_points = 0;            /* no indexing triangles in RDS output */
  231.     
  232.     point_max = 0;                /* size of index points                        */
  233.     
  234.     algorithm = 2;                /* use improved RDS algorithm                */ 
  235.  
  236.     color_back = 0;            /* use black and white palette            */
  237.     
  238.     map_file = 0;                /* no background map file                     */
  239.     
  240.     field = 2;              /* field is 1/2 the distance to image    */
  241.     
  242.     printer = NULL;            /* no list device                                */
  243.     
  244.     newval = 0xFFFF;            /* adaptive background replacement         */
  245.  
  246.     if (argc < 3)
  247.     {
  248.         showparms();
  249.  
  250.         exit(0);
  251.     }
  252.  
  253.     iname = argv[1];
  254.    oname = argv[2];
  255.  
  256.     for(i=3; i<argc; i++)
  257.     {
  258.         if(argv[i][0] == '+' || argv[i][0] == '-' || argv[i][0] == '/')
  259.         {
  260.             switch (argv[i][1])
  261.             {
  262.                 case    '?':    showparms();
  263.                                 break;
  264.                 case    'a':
  265.                 case    'A':    if(argv[i][2] == '\0') error("Missing algorithm number\n");
  266.                                 algorithm = atoi(argv[i]+2);
  267.                                 if(algorithm < 1 || algorithm > 3) error("Algorithm number, %i, is out of range\n", algorithm);
  268.                                 break;
  269.                 case    'b':
  270.                 case    'B':    if(argv[i][2] == '\0') error("Missing adaptive background substitution value\n");
  271.                                 adapt = atoi(argv[i]+2);
  272.                                 if(adapt < 1 || adapt > 64) error("Adaptive background offset, %i, is out of range\n", adapt);
  273.                                 break;
  274.                 case    'c':
  275.                 case    'C':    color_back = 1;
  276.                                 break;
  277.                 case    'd':
  278.                 case    'D':    if(argv[i][2] == '\0') error("Missing density value\n");
  279.                                 density = atoi(argv[i]+2);
  280.                                 if(density < 0 || density > 100) error("Density value, %i, is out of range\n", density);
  281.                                 break;
  282.                 case    'f':
  283.                 case    'F':    if(argv[i][2] == '\0') error("Missing depth of field value\n");
  284.                                 field = atoi(argv[i]+2);
  285.                                 if(field < 1 || field > 16) error("Depth of field value, %i, is out of range\n", field);
  286.                                 break;
  287.                 case    'i':
  288.                 case    'I':    index_points = 1;
  289.                                 break;
  290.                 case    'm':
  291.                 case    'M':    if(argv[i][2] == '\0') error("Missing map file name\n");
  292.                                bname = &argv[i][2];
  293.                                 map_file = 1;
  294.                                 break;
  295.                 case    'n':
  296.                 case    'N':    direction = 1;
  297.                                 break;
  298.                 case    'p':
  299.                 case    'P':    if(argv[i][2] == '\0') error("Missing printer device name\n");
  300.                                printer = &argv[i][2];
  301.                                 break;
  302.                case    'r':
  303.                 case    'R':    if(argv[i][2] == '\0') error("Missing random seed value\n");
  304.                                 seed = atoi(argv[i]+2);
  305.                                 break;
  306.                case    's':
  307.                 case    'S':    if(argv[i][2] == '\0') error("Missing strip count value\n");
  308.                                 stripc = atoi(argv[i]+2);
  309.                                 break;
  310.                 case    't':
  311.                 case    'T':    outfile = 1;
  312.                                 break;
  313.                 case    'v':
  314.                 case    'V':    display = 1;
  315.                                 break;
  316.                 default:        error("Unknown option: %s\n", argv[i]);
  317.             }
  318.         }
  319.         else error("Invalid switch\n");
  320.  
  321.     }
  322.  
  323.     if(map_file)
  324.     {
  325.         if(display) error("Video display is not available with bit-mapped background files\n");
  326.  
  327.         if(outfile) error("Output format must be GIF\n");
  328.  
  329.         if(color_back) error("Random color and bit-mapped color are mutually exclusive\n");
  330.     }
  331.  
  332.  
  333.     oldval = (direction) ? 1 : 0xFFFF; 
  334.  
  335.     ifile = fopen(iname, "rb");
  336.  
  337.     if (ifile == (FILE *)NULL)    error("Cannot open input file \"%s\".", iname);
  338.  
  339.     read_header_data(&xres, &yres);
  340.  
  341.     printf("xres: %d, yres: %d\n", xres, yres);
  342.    
  343.     printf("zmin: %u, zmax: %u\n", (unsigned) zmin, (unsigned) zmax);
  344.  
  345.     if((stripc < 1) || (stripc > xres)) error("Strip count value, %i, is out of range\n", stripc);
  346.  
  347.     stripw = xres / stripc;
  348.  
  349.     if(map_file)
  350.     {
  351.         bfile = fopen(bname, "rb");
  352.  
  353.         if (bfile == (FILE *)NULL)    error("Cannot open background map file \"%s\".", bname);
  354.  
  355.         read_background_header(&bxres, &byres);
  356.  
  357.         if(xres != bxres || yres != byres) error("Background map file resolution (%i x %i) does not match input resolution\n", bxres, byres);
  358.  
  359.         if(byres < stripw) error("Background map file resolution (%i x %i) is less than strip width, %i\n", bxres, byres, stripw);
  360.     }
  361.  
  362.     point_max = yres >> 6;
  363.     
  364.     if(adapt) 
  365.     {
  366.         newval = zmin - ((zmax - zmin) / adapt);
  367.  
  368.         zmin = newval;
  369.     }
  370.     
  371.     limit = (long) density * RAND_MAX / 100;
  372.  
  373.     if((seed < 1) || (seed > RAND_MAX)) error("Random number seed value, %i, is out of range\n", seed);
  374.  
  375.     srand(seed);
  376.     
  377.     if ((depths = (unsigned int *)malloc(xres * sizeof(unsigned int))) == NULL) error("Failed to allocate data row array\n");
  378.  
  379.    if ((odata = malloc(xres * sizeof(unsigned char))) == NULL) error("Failed to allocate the output image buffer\n");
  380.  
  381.     if(algorithm == 3)
  382.     {
  383.         if((same = malloc(xres * sizeof(int))) == NULL) error("Unable to allocate constraint array\n");
  384.  
  385.         stripw = xres >> 3;                                /* strip width for index points            */
  386.     }
  387.  
  388.     num = (zmax - zmin) * field + zmin;                /* numerator for depth calculation        */
  389.     den = 2 * (zmax - zmin) * field + zmin;        /* denumerator for depth calculation    */
  390.  
  391.     scale = xres >> 2;                                    /* scale for depth calculation            */
  392.  
  393.     if(printer != NULL)
  394.     {
  395.         if((printy = (unsigned char **) malloc(yres * sizeof(unsigned char *))) == NULL) error("Unable to allocate print lines array\n");
  396.  
  397.         if(color_back != 0) printf("Monochrome RDS will be generated for printer\n");
  398.  
  399.         color_back = 0;
  400.     }
  401.  
  402.     if(outfile == 1)
  403.     {
  404.         printf("Generating TGA output file\n");
  405.     }
  406.     else
  407.     {
  408.         printf("Generating GIF output file\n");
  409.  
  410.         if(!color_back)
  411.         {    
  412.             for(i=0; i<256; i++)
  413.             {
  414.                 red[i]    = i;
  415.                 green[i] = i;
  416.                 blue[i]    = i;
  417.             }
  418.         }
  419.         if(map_file)
  420.         {    
  421.             for(i=0, j=0; i<256; i++)
  422.             {
  423.                 red[i]    = bcmap[j++];
  424.                 green[i] = bcmap[j++];
  425.                 blue[i]    = bcmap[j++];
  426.             }
  427.         }
  428.     }
  429.  
  430.    if(display)
  431.     {
  432.         switch(xres)
  433.         {
  434.             case 320:    if(yres != 200) error("Unable to display %i by %i image\n", xres, yres); 
  435.                             driver = CGA;
  436.                             mode = 1;    
  437.                             break;
  438.             case 640:    if(yres == 480)
  439.                             {
  440.                                 driver = VGA;
  441.                                 mode = 2;
  442.                                 break;
  443.                             }
  444.                             driver = EGA;
  445.                             if(yres == 350)
  446.                             {
  447.                                 mode = 1;
  448.                                 break;
  449.                             }
  450.                             if(yres == 200)
  451.                             {
  452.                                 mode = 0;
  453.                                 break;
  454.                             }
  455.             default:        error("Unable to display %i by %i image\n", xres, yres); 
  456.         }
  457.  
  458.         initgraph(&driver, &mode, 0);
  459.  
  460.         errcode = graphresult();
  461.  
  462.         if(errcode != grOk)
  463.         {
  464.             printf("%s\n", grapherrormsg(errcode));
  465.             exit(0);
  466.         }
  467.     }
  468.  
  469.     if(outfile == 1)
  470.     {
  471.         TGAEncode(oname,                        /* file name            */
  472.                      xres,yres);                /* image size            */
  473.     }
  474.     else
  475.     {
  476.         GIFEncode(oname,                        /* file name             */
  477.                      xres, yres,                /* image size         */
  478.                      0,                      /* no interlace         */
  479.                      0,                      /* bkg color             */
  480.                      8,                      /* bits per pixel     */
  481.                      red, green, blue,         /* palette arrays     */
  482.                      get_pix);                     /* pixel function     */
  483.     
  484.     }
  485.  
  486.     if(printer != NULL) printout();
  487.  
  488.     if(display == 0)
  489.     {
  490.         printf("\n");
  491.     }
  492.     else
  493.     {
  494.         beep();
  495.     
  496.         while(!kbhit());
  497.  
  498.         closegraph();
  499.     }
  500.  
  501.     if(map_file) fclose(bfile);
  502.  
  503.     fclose(ifile);
  504. }
  505.  
  506. /*                                                                                             */
  507. /*  Generate a line of RDS from a line of depth data (left to right)            */
  508. /*                                                                                                   */    
  509. /*  Three RDS algorithms are available                                                    */    
  510. /*                                                                                                   */    
  511. /*  Algorithm 1:                                                                                   */    
  512. /*                                                                                                   */    
  513. /*     First just generate random dots across the line                                */
  514. /*                                                                                                    */
  515. /*     Next go through depth data, adjusting pixels according to following        */
  516. /*                                                                                                    */
  517. /*                o = strip width - depth[i]                                                    */
  518. /*                                                                                                    */
  519. /*                pixel[i+o] = pixel[i-o]                                                        */
  520. /*                                                                                                    */
  521.  
  522.  
  523. void gen_rds_line(int width)
  524. {
  525.     int                d, i, j, n, o, w;
  526.  
  527.     long           l, z;
  528.  
  529.     unsigned int    k;
  530.  
  531.     long                inc, dt;
  532.  
  533.  
  534.     w = stripw / field;                                /* limit useable strip by depth of field    */
  535.  
  536.     z = zmax - zmin;                                    /* calculate useable portion of strip        */
  537.  
  538.     if(algorithm == 1)
  539.     {
  540.         n = 0;                                            /* initialize left-most pixel                    */
  541.     
  542.         /* first, just generate background dots */
  543.     
  544.         if(map_file)
  545.         {
  546.             for(i=0; i<stripw; i++)                    /* get dots from background map                */
  547.             {
  548.                 if((k = bget_map()) == bending) error("Premature EOF in map file, %s\n", bname);
  549.  
  550.                 odata[i] = k;
  551.             }
  552.  
  553.             for(j=i; j<bxres; j++)
  554.             {
  555.                 if((k = bget_map()) == bending) error("Premature EOF in map file, %s\n", bname);
  556.  
  557.                 odata[j] = k;                            /* fill-in entire line                            */
  558.             }
  559.         }
  560.         else
  561.         {
  562.             if(color_back)                                /* if random color background                    */
  563.             {
  564.                 for(i=0; i<stripw; i++) odata[i] = ((long) rand() << 4) / RAND_MAX;
  565.             }
  566.             else                                            /* if back and white background                */
  567.             {
  568.                 for(i=0; i<stripw; i++) odata[i] = (rand() < limit) ? 0 : 255;
  569.             }
  570.         }
  571.     
  572.         for(; i<width; i++)
  573.         {
  574.             if(!map_file)
  575.             {
  576.                 if(color_back)
  577.                 {
  578.                     odata[i] = ((long) rand() << 4) / RAND_MAX;
  579.                 }
  580.                 else
  581.                 {
  582.                     odata[i] = (rand() < limit) ? 0 : 255;
  583.                  }
  584.             }
  585.         
  586.             l = depths[i] & 0xFFFF;                        /* extract depth value                                     */
  587.                 
  588.             o = (((l - zmin) * w) / z);                /* scale to strip width                                     */
  589.  
  590.             d = (i - stripw + o);                        /* calculate displacement to corresponding pixel */
  591.         
  592.             if(d >= n)                                        /* if from pixel right of last from pixel             */ 
  593.             {
  594.                 odata[i] = odata[d];                        /* copy depth adjusted pixel from previous strip */
  595.  
  596.                 n = d;                                        /* new left-most pixel                                     */
  597.             }
  598.         }
  599.     }
  600.  
  601.     if(algorithm == 2)
  602.     {
  603.         n = 0;                                                /* left-most pixel    */
  604.  
  605.         /* first just generate random dots    */
  606.     
  607.         if(map_file)
  608.         {
  609.             for(i=0; i<bxres; i++)
  610.             {
  611.                 if((k = bget_map()) == bending) error("Premature EOF in map file, %s\n", bname);
  612.                 odata[i] = k;
  613.             }
  614.         }
  615.         else
  616.         {
  617.             if(color_back)
  618.             {
  619.                 for(i=0; i<width; i++) odata[i] = ((long) rand() << 4) / RAND_MAX;
  620.             }
  621.             else
  622.             {
  623.                 for(i=0; i<width; i++) odata[i] = (rand() < limit) ? 0 : 255;
  624.             }
  625.         }
  626.         
  627.         /* now go back and adjust for depth    */
  628.     
  629.         for(i=0; i<width; i++)
  630.         {
  631.             l = depths[i] & 0xFFFF;                            /* extract depth value                  */
  632.                 
  633.             o = (num - l) * scale / (den - l);            /* calculate separation             */
  634.  
  635.             d = i - (o >> 1);                                    /* left pixel is 1/2 offset back    */
  636.  
  637.             if((d > -1) && ((d+o) < width))                /* if both pixels visible            */                                
  638.             {
  639.                 if(d >= n)                                        /* if visible by both eyes            */
  640.                 {
  641.                     odata[d+o] = odata[d];                    /* propagate pixel forward            */
  642.  
  643.                     n = d;                                        /* new left most pixel                */
  644.                 }
  645.             }
  646.         }
  647.     }
  648.  
  649.     if(algorithm == 3)
  650.     {
  651.         /* initialize same array */
  652.         
  653.         for(i=0; i<width; i++) same[i] = i;
  654.  
  655.         /* scan line for pixel constraints */
  656.  
  657.         for(i=0; i<width; i++)
  658.         {
  659.             l = depths[i] & 0xFFFF;                                /* extract depth value                        */
  660.  
  661.             sep = (num - l) * scale / (den - l);            /* calculate separation length            */
  662.  
  663.             left = i - sep / 2;                                    /* left is current - 1/2 separation        */
  664.             right = sep + left;                                    /* right is left plus separation            */
  665.  
  666.             if(left >= 0 && right < width)                    /* if both pixels on the screen            */
  667.             {
  668.                 w = 1;                                                /* assume point is visible                    */
  669.  
  670.                 dt = depths[i] & 0xFFFF - zmin;                /* get relative depth value                */
  671.  
  672.                 inc = (16 * field * z - 8 * dt) / xres;    /* depth increase per unit of width        */  
  673.  
  674.                 for(j=1; dt<z; j++)                                /* while relative depth within limits    */
  675.                 {
  676.                     dt += inc;                                        /* increment relative depth value        */
  677.  
  678.                     l = dt + zmin;                                    /* convert to absolute depth value        */
  679.  
  680.                     if((i-j) >= 0 && depths[i-j] > l)        /* if on screen and occluded                */
  681.                     {
  682.                         w = 0;                                        /* pixel is not visible (constrained)    */
  683.                         break;
  684.                     }
  685.  
  686.                     if((i+j) < width && depths[i+j] > l)    /* if on screen and occluded                */
  687.                     {
  688.                         w = 0;                                        /* pixel is not visible (constrained)    */ 
  689.                         break;
  690.                     }
  691.                 } 
  692.                 
  693.                 if(w)                                                    /* if visible                                                */
  694.                 {
  695.                     if(same[left] < right)                        /* if previous constraint is left of new            */ 
  696.                     {
  697.                         same[same[left]] = right;                /* previous node is constrained to new                */
  698.  
  699.                         same[left] = right;                        /* new right-most constraint on this pixel        */
  700.                     }
  701.                     else
  702.                     {
  703.                         same[right] = same[left];                /* right pixel is constrained to further right    */
  704.                     }
  705.                 }
  706.             }
  707.         }
  708.         
  709.         for(i=width-1; i>=0; i--)                /* scan backwards        */
  710.         {
  711.             if(map_file) if((k = bget_map()) == bending) error("Premature EOF in map file, %s\n", bname);
  712.  
  713.             if(same[i] == i)                         /* if unconstrained    */
  714.             {
  715.                 if(map_file)
  716.                 {
  717.                     odata[i] = k;                     /* get color from background map    */
  718.                 }
  719.                 else
  720.                 {
  721.                     if(color_back)                    /* if random color background        */                                    
  722.                     {
  723.                         odata[i] = ((long) rand() << 4) / RAND_MAX;
  724.                     }
  725.                     else                                /* if black and white background    */
  726.                     {
  727.                         odata[i] = (rand() < limit) ? 0 : 255;
  728.                     }
  729.                 }
  730.             }
  731.             else
  732.             {
  733.                 odata[i] = odata[same[i]];        /* copy cvonstrained pixel            */
  734.             }
  735.         }
  736.     }
  737. }
  738.  
  739.  
  740. /*                                                       */
  741. /* Open a grey-scale Targa for output.             */
  742. /*                                                   */
  743.  
  744. void open_targa_file(char * oname, unsigned width, unsigned height)
  745. {
  746.    unsigned char tgaheader[18];
  747.  
  748.     memset(tgaheader, 0, 18);
  749.    
  750.     if ((ofile = fopen(oname, "wb")) == NULL)    error("Failed to open output file %s\n", oname);
  751.  
  752.     tgaheader[2] = 3;
  753.    tgaheader[12] = (unsigned char) (width & 0xFF);
  754.    tgaheader[13] = (unsigned char) ((width >> 8) & 0xFF);
  755.    tgaheader[14] = (unsigned char) (height & 0xFF);
  756.    tgaheader[15] = (unsigned char) ((height >> 8) & 0xFF);
  757.    tgaheader[16] = 8;
  758.    tgaheader[17] = 0x20;
  759.    
  760.     fwrite(tgaheader, 18, 1, ofile);
  761. }
  762.  
  763. /*                                                             */
  764. /* Write a line of greyscale points to a Targa file  */
  765. /*                                                               */
  766.  
  767. void write_targa_line(unsigned width)
  768. {
  769.    int i;
  770.  
  771.     for (i=0;i<width;i++) fputc(odata[i], ofile);
  772. }
  773.  
  774. /*                                                       */
  775. /* Read and evaluate one unit of input data    */
  776. /*                                                  */
  777.  
  778. unsigned int get_value()
  779. {
  780.     int                 i, j, k;
  781.  
  782.     register int    r, g, b;
  783.  
  784.     unsigned int     val;
  785.  
  786.     unsigned char    bytes[4];
  787.  
  788.  
  789.     if(intype)
  790.     {
  791.         /*                                                */
  792.         /* get input data from GIF decoder    */
  793.         /*                                                */
  794.  
  795.         if((k = idecode_gif()) < 0) error("Error reading input file %s\n", iname);
  796.     
  797.         if(k == iending) return(iending);
  798.  
  799.         k = k & 0xFF;
  800.  
  801.         j = icmsize * k;
  802.  
  803.         val = icmap[j++] << 8 | icmap[j];
  804.     }
  805.     else
  806.     {
  807.         /*                                                */
  808.         /* get input data from TGA file        */
  809.         /*                                                */
  810.  
  811.         if (ftype == 2)
  812.         {
  813.             /*                                              */
  814.             /* input data is 8/16/24 bit rgb    */
  815.             /*                                              */
  816.  
  817.             switch(ipsize)
  818.             {
  819.                 case 1:    if((r = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
  820.                             val = r << 8;
  821.                             break;
  822.  
  823.                 case 2:    if((g = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
  824.                             if((r = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
  825.                        val = r << 8 | g;
  826.                             break;
  827.  
  828.                 case 3:    if((g = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
  829.                             if((g = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
  830.                             if((r = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
  831.                        val = r << 8 | g;
  832.                             break;
  833.  
  834.                 default:    error("Invalid color map byte count, %i\n", ipsize);
  835.             }
  836.         }
  837.         else
  838.         {
  839.             /*                                              */
  840.             /* input data is color map index    */
  841.             /*                                              */
  842.  
  843.             if ((k = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
  844.  
  845.             j = icmsize * k;
  846.  
  847.             if (ipsize == 2)
  848.             {
  849.                 val = icmap[j++] | (icmap[j] << 8);
  850.           }
  851.           else
  852.             {
  853.                 val = icmap[++j] | (icmap[++j] << 8);
  854.           }
  855.        }
  856.     }
  857.  
  858.     if(direction != 0) val = -val;
  859.  
  860.     return(val);
  861. }
  862.  
  863.  
  864. /*                                                           */
  865. /* Read next byte from background map file        */
  866. /*                                                         */
  867.  
  868. unsigned int bget_map()
  869. {
  870.     int                 i, j;
  871.  
  872.     unsigned int     k;
  873.  
  874.  
  875.     if((k = bdecode_gif()) < 0) error("Error reading map file %s\n", bname);
  876.     
  877.     if(k == bending) return(bending);
  878.  
  879.     k = k & 0xFF;
  880.  
  881.     return(k);
  882. }
  883.  
  884.         
  885. /*                                                           */
  886. /* Add index points to top of image                    */
  887. /*                                                         */
  888.  
  889. void add_index(int line)
  890. {
  891.     int    i, c, d;
  892.  
  893.     c = point_max - line;
  894.  
  895.     d = ((xres - stripw) >> 1) - c;
  896.  
  897.     for(i=0; i<c<<1; i++) odata[d+i] = 0;
  898.  
  899.     d = ((xres + stripw) >> 1) - c;
  900.  
  901.     for(i=0; i<c<<1; i++) odata[d+i] = 0;
  902. }
  903.  
  904. /*                                                           */
  905. /* Read a line's worth of the input file             */
  906. /*                                                         */
  907.  
  908. void    read_data_line(int width)
  909. {
  910.     int                i, j, k;
  911.  
  912.     unsigned int     val;
  913.  
  914.     unsigned char    bytes[4];
  915.  
  916.  
  917.     for (i=0;i<width;i++)
  918.     {
  919.         val = get_value();
  920.     
  921.         if(intype) if(val == iending) error("Premature end of object reading input GIF file %s\n", iname);
  922.  
  923.         if(adapt) if(val == oldval) val = newval;
  924.  
  925.         depths[i] = val;
  926.     }
  927. }
  928.  
  929. /*                                                 */
  930. /* Read next entry for GIF output routine    */
  931. /*                                                   */
  932.  
  933. int get_pix(int x, int y)
  934. {
  935.     int            i, val;
  936.  
  937.     static int    line = -1;    
  938.  
  939.     if(y != line)
  940.     {
  941.         line = y;
  942.         
  943.         if(display == 0) printf("Line: %d  \r", y);
  944.  
  945.         if(line > yres) error("Request for invalid input location [%i][%i]\n", x, y);
  946.  
  947.         read_data_line(xres);
  948.  
  949.         gen_rds_line(xres);
  950.  
  951.         if(index_points) if(y<point_max) add_index(y);
  952.  
  953.         if(printer != NULL) add_line(xres, y);
  954.  
  955.        test_exit;
  956.  
  957.         if(display)
  958.         {
  959.             for(i=0; i<xres; i++)
  960.             {
  961.                 putpixel(i, y, odata[i]);
  962.             }
  963.         }
  964.     }
  965.  
  966.     val = odata[x];
  967.  
  968.     return(val);
  969.  
  970. }
  971.  
  972.  
  973. /*                                                 */
  974. /* Read header portion of input file        */
  975. /*                                                   */
  976.  
  977. void read_header_data(unsigned *xsize, unsigned *ysize)
  978. {
  979.     int                i, j, k, l;
  980.  
  981.     unsigned char     header[18];
  982.  
  983.     unsigned char    bytes[4];
  984.  
  985.     int                 width, height;
  986.  
  987.     long                count, val, position;
  988.  
  989.  
  990.     zmax = 0;
  991.     zmin = 65536;
  992.  
  993.    if(fread(&header[0], 3, 1, ifile) != 1) error("Couldn't read header from input file: %s\n", iname);
  994.  
  995.     intype = strncmp((const char *) header, GIFstr, 3);
  996.  
  997.     intype = (intype) ? 0 : 1;
  998.  
  999.     if(intype)
  1000.     {
  1001.         if(fread(&header[3], 10, 1, ifile) != 1) error("Couldn't read GIF header from input file %s\n", iname);
  1002.  
  1003.         if(!(header[10] & 0x80)) error("Input file %s, has no color map\n", iname);
  1004.  
  1005.         icmlen     = 1 << ((header[10] & 0x0F) + 1);
  1006.         icmsize    = 3; 
  1007.  
  1008.        if (icmlen > 0)
  1009.         {
  1010.           if ((icmap = malloc(sizeof(unsigned char)*icmsize*icmlen)) == NULL) error("Failed to allocate memory for color map\n");
  1011.  
  1012.             for (i=0;i<icmlen * icmsize;i++)
  1013.             {
  1014.              if ((k = fgetc(ifile)) == EOF) error("Premature EOF in color map\n");
  1015.          
  1016.                 icmap[i] = (unsigned char)k;
  1017.           }
  1018.        }
  1019.  
  1020.         k = 0;
  1021.  
  1022.         while(k != EOF)
  1023.         {
  1024.             switch(k = fgetc(ifile))
  1025.             {
  1026.                  case ';':    k = EOF;
  1027.                                 break;
  1028.  
  1029.                 case '!':    if((k = fgetc(ifile)) == EOF) error("Premature EOF in input file, %s\n", iname);
  1030.                                 if((k = fgetc(ifile)) == EOF) error("Premature EOF in input file, %s\n", iname);
  1031.                                 for(i=k; i>0; i--)  if((k = fgetc(ifile)) == EOF) error("Premature EOF in input file, %s\n", iname);
  1032.                                 break;
  1033.  
  1034.                 case ',':    if (fread(header, 9, 1, ifile) != 1) error("Couldn't read object header from input file: %s\n", iname);
  1035.  
  1036.                                 width     = header[4] | header[5] << 8;
  1037.                                 height =    header[6] | header[7] << 8;
  1038.                                 
  1039.                                 if ((header[8] & 0x80) == 0x80)
  1040.                                 {
  1041.                                     i = 1 << ((header[10] & 0x0F) + 1);
  1042.                                     for(; i<0; i++) if((k = fgetc(ifile)) == EOF) error("Premature EOF in input file, %s\n", iname);
  1043.                                 }
  1044.                                 
  1045.                                 position = ftell(ifile);
  1046.                                 
  1047.                                 if((k = ialloc_gif_stacks()) != 0) error("Unable to allocate stack space for GIF decoder\n");
  1048.     
  1049.                                 printf("scanning GIF input for depth ranges\n");
  1050.                                 
  1051.                                 if((val = iinit_gif_decoder()) != 0) error("Error %d, initializing GIF decoder\n", val);
  1052.                                 
  1053.                                 while(val != iending)
  1054.                                 {
  1055.                                     val = get_value();
  1056.  
  1057.                                     if((!adapt) || (val != oldval))
  1058.                                     {
  1059.                                         if(zmax < val) zmax = val;
  1060.                                         if(zmin > val) zmin = val;
  1061.                                     }
  1062.                                 }
  1063.  
  1064.                                 if(ibad_code_count > 0) error("%d out of range codes encountered in GIF input file %s\n", ibad_code_count, iname);
  1065.                                 
  1066.                                 fseek(ifile, position, SEEK_SET);
  1067.                                 
  1068.                                 if((k = iinit_gif_decoder()) != 0) error("Error %d, reinitializing GIF decoder\n", k);
  1069.     
  1070.                                 k = EOF;
  1071.                                 
  1072.                                 break;
  1073.  
  1074.                 default:        error("Unknown GIF format byte - %c\n", k);
  1075.             }
  1076.         }
  1077.     }
  1078.     else
  1079.     {
  1080.         if(fread(&header[3], 15, 1, ifile) != 1) error("Couldn't read TGA header from input file %s\n", iname);
  1081.      
  1082.         idlen      = header[0];
  1083.        ftype      = header[2];
  1084.        icmlen    = header[5] | header[6] << 8;
  1085.        icmsize    = header[7];
  1086.        width      = header[12] | header[13] << 8;
  1087.        height     = header[14] | header[15] << 8;
  1088.        ipsize      = header[16];     
  1089.  
  1090.        if (!((ftype == 1 && ipsize <= 8) ||    (ftype == 2 && (ipsize == 16 || ipsize == 24)) ||    (ftype == 3 && ipsize == 8)))
  1091.         {
  1092.             error("Unsupported Targa type: %d\n", ftype);
  1093.         }
  1094.  
  1095.         if (icmlen > 256) error("Can't handle color maps of length %u\n", icmlen);
  1096.  
  1097.         if (icmlen > 0 && (icmsize != 16 && icmsize != 24)) error("Color maps entries must be 16 or 24 bits, not: %d\n", icmsize);
  1098.        else icmsize /= 8;
  1099.  
  1100.        if (ipsize != 8 && ipsize != 16 && ipsize != 24) error("%d bits/pixel not supported in height field, must be 8/16/24\n", ipsize);
  1101.        else ipsize /= 8;
  1102.  
  1103.        if (idlen > 0 && fread(idbuf, idlen, 1, ifile) != 1) error("Reading identification field of %s\n", iname);
  1104.  
  1105.        if (icmlen > 0)
  1106.         {
  1107.           if ((icmap = malloc(sizeof(unsigned char)*icmsize*icmlen)) == NULL) error("Failed to allocate memory for color map\n");
  1108.  
  1109.             for (i=0;i<icmlen * icmsize;i++)
  1110.             {
  1111.              if ((k = fgetc(ifile)) == EOF) error("Premature EOF in color map\n");
  1112.          
  1113.                 icmap[i] = (unsigned char)k;
  1114.           }
  1115.        }
  1116.  
  1117.         if (ftype == 1 && icmap == NULL) error("Targa color map must have entries\n");
  1118.  
  1119.         position = ftell(ifile);
  1120.  
  1121.         printf("scanning TGA input for depth ranges\n");
  1122.  
  1123.         for(count= (long) width*height; count>0; count--)
  1124.         {
  1125.             val = get_value() & 0xFFFF;
  1126.  
  1127.             if((!adapt) || (val != oldval))
  1128.             {
  1129.                 if(zmax < val) zmax = val;
  1130.                 if(zmin > val) zmin = val;
  1131.             }
  1132.         }
  1133.     
  1134.         fseek(ifile, position, SEEK_SET);
  1135.     }
  1136.  
  1137.       *xsize = width;
  1138.       *ysize = height;
  1139. }
  1140.  
  1141.  
  1142. /*                                                 */
  1143. /* Read header portion of background file    */
  1144. /*                                                   */
  1145.  
  1146. void read_background_header(unsigned *xsize, unsigned *ysize)
  1147. {
  1148.     int                i, j, k, l;
  1149.  
  1150.     unsigned char     header[18];
  1151.  
  1152.     unsigned char    bytes[4];
  1153.  
  1154.     int                 width, height;
  1155.  
  1156.     long                count, val, position;
  1157.  
  1158.  
  1159.    if(fread(&header[0], 3, 1, bfile) != 1) error("Couldn't read header from map file: %s\n", bname);
  1160.  
  1161.     if((i = strncmp((const char *) header, GIFstr, 3)) != 0) error("Background map file, %s, is not in GIF format\n", bname);
  1162.  
  1163.     if(fread(&header[3], 10, 1, bfile) != 1) error("Couldn't read GIF header from map file %s\n", bname);
  1164.  
  1165.     if(!(header[10] & 0x80)) error("Background map file %s, has no color map\n", bname);
  1166.  
  1167.     bcmlen     = 1 << ((header[10] & 0x0F) + 1);
  1168.     bcmsize        = 3; 
  1169.  
  1170.       if (bcmlen > 0)
  1171.     {
  1172.          if ((bcmap = malloc(sizeof(unsigned char)*bcmsize*bcmlen)) == NULL) error("Failed to allocate memory for color map\n");
  1173.  
  1174.         for (i=0;i<bcmlen * bcmsize;i++)
  1175.         {
  1176.             if ((k = fgetc(bfile)) == EOF) error("Premature EOF in color map\n");
  1177.          
  1178.             bcmap[i] = (unsigned char)k;
  1179.          }
  1180.       }
  1181.  
  1182.     k = 0;
  1183.  
  1184.     while(k != EOF)
  1185.     {
  1186.         switch(k = fgetc(bfile))
  1187.         {
  1188.             case ';':    k = EOF;
  1189.                             break;
  1190.  
  1191.             case '!':    if((k = fgetc(bfile)) == EOF) error("Premature EOF in map file, %s\n", bname);
  1192.                             if((k = fgetc(bfile)) == EOF) error("Premature EOF in map file, %s\n", bname);
  1193.                             for(i=k; i>0; i--)  if((k = fgetc(bfile)) == EOF) error("Premature EOF in map file, %s\n", bname);
  1194.                             break;
  1195.  
  1196.             case ',':    if (fread(header, 9, 1, bfile) != 1) error("Couldn't read object header from map file: %s\n", bname);
  1197.  
  1198.                             width     = header[4] | header[5] << 8;
  1199.                             height =    header[6] | header[7] << 8;
  1200.                             
  1201.                               *xsize = width;
  1202.                               *ysize = height;
  1203.  
  1204.                             if ((header[8] & 0x80) == 0x80)
  1205.                             {
  1206.                                 i = 1 << ((header[10] & 0x0F) + 1);
  1207.                                 for(; i<0; i++) if((k = fgetc(bfile)) == EOF) error("Premature EOF in map file, %s\n", bname);
  1208.                             }
  1209.                             
  1210.                             if((k = balloc_gif_stacks()) != 0) error("Unable to allocate stack space for GIF decoder\n");
  1211.     
  1212.                             if((k = binit_gif_decoder()) != 0) error("Error %d, initializing GIF decoder\n", k);
  1213.  
  1214.                             k = EOF;
  1215.                             
  1216.                             break;
  1217.  
  1218.             default:        error("Unknown GIF format byte - %c\n", k);
  1219.         }
  1220.     }
  1221. }
  1222.  
  1223.  
  1224. /*                                                             */
  1225. /*  Generate RDS from Targa depth data                 */
  1226. /*                                                                   */    
  1227.  
  1228. void TGAEncode(char * oname, int width, int height)
  1229. {
  1230.    int         i, j;
  1231.  
  1232.     open_targa_file(oname, width, height);
  1233.  
  1234.     for (i=height;i>0;i--)
  1235.     {
  1236.         if(display == 0) printf("Line: %d  \r", i);
  1237.  
  1238.         read_data_line(width);
  1239.  
  1240.         gen_rds_line(xres);
  1241.  
  1242.         if(index_points) if(i<point_max) add_index(i);
  1243.  
  1244.         if(printer != NULL) add_line(xres, i);
  1245.  
  1246.         if(display)
  1247.         {
  1248.             for(j=0; j<width; j++)
  1249.             {
  1250.                 if(odata[j] == 255) putpixel(j, height-i-1, WHITE);
  1251.             }
  1252.         }
  1253.  
  1254.         test_exit;
  1255.         
  1256.         write_targa_line(width);
  1257.     }
  1258.  
  1259.     fclose(ofile);
  1260. }
  1261.  
  1262. /*                                               */
  1263. /* Display command line parameters            */
  1264. /*                                               */
  1265.  
  1266. void    showparms()
  1267. {
  1268.     printf("\nUsage: rds input.ext output.ext options\n\n");
  1269.     printf("options: -a#         : Algirithm number, range 1 or 2 (default 1)\n");
  1270.     printf("         -b###       : Adaptive background value, range 1 to 64\n");
  1271.     printf("         -d###       : Density value, range 0 to 100 (default 50)\n");
  1272.     printf("         -i          : Add indexing triangles to top of RDS\n");
  1273.     printf("         -mccc.ext : Background map file name\n");
  1274.     printf("         -n          : Produce a precedence reversed (negative) image\n");
  1275.     printf("         -pcc         : Print image on named graphics printer\n");
  1276.     printf("         -r#####     : Seed number for random generator, range 1-32767 (default 1)\n");
  1277.     printf("         -s###       : Strip count, range 1-width (default 8)\n");
  1278.     printf("         -t          : Generate type 3 TGA output file\n");
  1279.     printf("         -v          : Display image on video while processing\n\n");
  1280. }
  1281.  
  1282.  
  1283. /*                                           */
  1284. /* Add line to printer array                */
  1285. /*                                           */
  1286.  
  1287. void add_line(int width, int line)
  1288. {
  1289.     int                    i, j, k;
  1290.  
  1291.     unsigned int         c;
  1292.  
  1293.     
  1294.     k = 0;
  1295.  
  1296.     if((printx = (unsigned char *) malloc(width >> 3)) == NULL) error("Unable to allocate print line %i\n", line);
  1297.  
  1298.     printy[line] = printx;
  1299.  
  1300.     for(i=0; i<width;)
  1301.     {
  1302.         c = 0;
  1303.  
  1304.         for(j=0; j<8; j++)
  1305.         {
  1306.             if((printer[0] == 'e') || (printer[0] == 'E'))
  1307.             {
  1308.                 c = c >> 1;
  1309.  
  1310.                 if(odata[i++] == 0) c += 0x80;
  1311.             }
  1312.             else
  1313.             {
  1314.                 c = c << 1;
  1315.  
  1316.                 if(odata[i++] == 0) c++;
  1317.             }
  1318.         }
  1319.         printx[k++] = c;
  1320.     }
  1321. }
  1322.  
  1323. /*                                           */
  1324. /* Print RDS on graphics printer            */
  1325. /*                                           */
  1326.  
  1327. void printout()
  1328. {
  1329.  
  1330.     switch(printer[0])
  1331.     {
  1332.         case 'e'    :
  1333.         case 'E'    : epsonout();
  1334.                       break;    
  1335.         case 'h'    :
  1336.         case 'H'    : hewlettout();
  1337.                       break;    
  1338.  
  1339.         default    : error("Unsupported printer type, %s\n", printer);
  1340.     }
  1341.  
  1342. }
  1343.  
  1344. /*                                                           */
  1345. /* Print RDS on epson 8/24-pin dot matrix printer    */
  1346. /*              incomplete                                    */
  1347.  
  1348. void epsonout()
  1349. {
  1350.     int        i, j, k;
  1351.  
  1352.     char        init_prt[] = { 0x1B, '3', 0x18, '\0' };
  1353.  
  1354.     char        init_line[] = { 0x1B, 'L', '\0', '\0' };
  1355.  
  1356.  
  1357.     init_line[2] = (yres << 1) & 0xFF;
  1358.     init_line[3] = (yres >> 7);
  1359.  
  1360.     for(i=0; i<3; i++) biosprint(PR_OUT, init_prt[i], LPT1);
  1361.  
  1362.     for(i=(xres>>3)-1; i>=0; i--)
  1363.     {
  1364.         for(j=0; j<4; j++) biosprint(PR_OUT, init_line[j], LPT1);
  1365.  
  1366.         for(j=0; j<yres; j++)
  1367.         {
  1368.             printx = printy[j];
  1369.  
  1370.             biosprint(PR_OUT, printx[i], LPT1);
  1371.             biosprint(PR_OUT, printx[i], LPT1);
  1372.         }
  1373.  
  1374.         biosprint(PR_OUT, 0x0D, LPT1);
  1375.         biosprint(PR_OUT, 0x0A, LPT1);
  1376.     }
  1377. }
  1378.  
  1379.  
  1380. /*                                                           */
  1381. /* Print RDS on Hewlett Packard Laser Jet                */
  1382. /*              incomplete                                    */
  1383.  
  1384. void hewlettout()
  1385. {
  1386.     int                    i, j, k;
  1387.  
  1388.     int                    xinc, yinc, inc;
  1389.  
  1390.     int                    left, top;
  1391.  
  1392.     unsigned char    *    byte;
  1393.  
  1394.     char    *                ctop;
  1395.  
  1396.     char    *                cleft;
  1397.  
  1398.     char                    init_res[] = { 0x1B, '*', 't', '3', '0', '0', 'R' };
  1399.  
  1400.     char                    set_top[] = { 0x1B, '&', 'a', '\0', '\0', '\0', 'R' };
  1401.  
  1402.     char                    set_left[] = { 0x1B, '&', 'a', '\0', '\0', '\0', 'H' };
  1403.  
  1404.     char                    init_line[] = { 0x1B, '*', '1', 'A' };
  1405.  
  1406.     char                    send_line[] = { 0x1B, '*', 'b', '\0', '\0', '\0', 'W' };
  1407.  
  1408.     char                    end_graph[] = { 0x1B, '*', 'r', 'B' };
  1409.  
  1410.  
  1411.     xinc = 3000/xres;
  1412.     yinc = 2400/yres;
  1413.  
  1414.     inc = (xinc < yinc) ? xinc : yinc;
  1415.  
  1416.     top  = (39600L - ((long) inc * xres * 12)) / 10;
  1417.     left = (30600L - ((long) inc * xres * 12)) / 10;
  1418.  
  1419.     ctop = itoa(top, ctop, 10);
  1420.     cleft = itoa(left, cleft, 10);
  1421.  
  1422.     strncpy(set_top[3], ctop, 3);
  1423.     strncpy(set_left[3], cleft, 3);
  1424.  
  1425.     for(i=0; i<7; i++) biosprint(PR_OUT, init_res[i], LPT1);
  1426.  
  1427.     for(i=0; i<7; i++) biosprint(PR_OUT, set_top[i], LPT1);
  1428.  
  1429.     for(i=0; i<7; i++) biosprint(PR_OUT, set_left[i], LPT1);
  1430.  
  1431.     for(i=0; i<5; i++) biosprint(PR_OUT, init_res[i], LPT1);
  1432.  
  1433.     for(i=(xres>>3)-1; i>=0; i--)
  1434.     {
  1435.         for(j=0; j<yres; j++)
  1436.         {
  1437.             printx = printy[j];
  1438.  
  1439.             for(k=0; k<4; k++) biosprint(PR_OUT, init_line[k], LPT1);
  1440.         
  1441.             for(k=0; k<7; k++) biosprint(PR_OUT, send_line[k], LPT1);
  1442.     
  1443.             for(k=0; k<inc; k++)
  1444.             {
  1445.  
  1446.             /* need some code here */
  1447.  
  1448.             }
  1449.         }
  1450.     }
  1451.  
  1452.     for(i=0; i<4; i++) biosprint(PR_OUT, end_graph[i], LPT1);
  1453. }
  1454.  
  1455.  
  1456. /*                                           */
  1457. /* Beep, beep                                    */
  1458. /*                                           */
  1459.  
  1460. void beep()
  1461. {
  1462.     nosound();
  1463.     sound(1300);
  1464.     delay(80);
  1465.     sound(1600);
  1466.     delay(80);
  1467.     sound(1900);
  1468.     delay(80);
  1469.     nosound();
  1470. }
  1471.  
  1472. /*                                           */
  1473. /* Display error message and exit        */
  1474. /*                                           */
  1475.  
  1476. void error(char *format, ...)
  1477. {
  1478.    va_list parms;
  1479.    
  1480.     /* fg_term(); */
  1481.    
  1482.     fprintf(stdout, "ERROR: ");
  1483.  
  1484.     va_start(parms, format);
  1485.    vfprintf(stdout, format, parms);
  1486.    va_end(parms);
  1487.    
  1488.     if(display) closegraph();
  1489.  
  1490.     exit(1);
  1491. }
  1492.  
  1493. /*                                                                                                    */
  1494. /*    GIF decoding routine                                                                        */
  1495. /*                                                                                                    */
  1496. /* This routine was borrowed from POVRAY which in turn borrowed the code     */
  1497. /* from FRACTINT.  It appears here in a somewhat modified format to             */
  1498. /*    conform to the requirements of my output driven logic.  Nevertheless,   */
  1499. /* I must give give appropriate credit to the orignal authors.                    */
  1500. /*                                                                                                    */
  1501. /* Based on :        DECODER.C - An LZW decoder for GIF                                */
  1502. /*                        Written by Steven A. Bennett                                        */
  1503. /*                        As inspired by Steve Wilhite                                        */
  1504. /*                        And modified by Bert Tyler and Timothy Wegner                */
  1505. /*                                                                                                 */
  1506.  
  1507. /*                                                        */
  1508. /* Get next byte of input for GIF decoder    */
  1509. /*                                                     */
  1510.  
  1511. int iget_byte()
  1512. {
  1513.     int    b;
  1514.     
  1515.     if((b = fgetc(ifile)) != EOF) return(b);
  1516.  
  1517.     printf("Premature EOF in GIF input file %s\n", iname);
  1518.  
  1519.     return(b);
  1520. }
  1521.  
  1522. /*                                                        */
  1523. /* get the next code from the GIF file        */
  1524. /*                                                        */
  1525.  
  1526. WORD iget_next_code()
  1527.   {
  1528.       WORD i, x;
  1529.  
  1530.       ULONG ret;
  1531.  
  1532.     if (ibit_count == 0)
  1533.       {
  1534.           if (ibyte_count <= 0)
  1535.        {
  1536.             /* Out of bytes in current block, so read next block */
  1537.  
  1538.           ibyte_ptr = ibyte_buff;
  1539.       
  1540.             if ((ibyte_count = iget_byte()) < 0) return(ibyte_count);
  1541.           else if (ibyte_count)
  1542.           {        
  1543.               for (i = 0; i < ibyte_count; ++i)
  1544.              {
  1545.                  if ((x = iget_byte()) < 0) return(x);
  1546.               
  1547.                     ibyte_buff[i] = (UTINY) x;
  1548.                 }
  1549.           }
  1550.       }
  1551.         ibyte = *ibyte_ptr++;
  1552.     
  1553.         ibit_count = 8;
  1554.         --ibyte_count;
  1555.     }
  1556.  
  1557.       ret = ibyte >> (8 - ibit_count);
  1558.       
  1559.     while (icurr_size > ibit_count)
  1560.    {
  1561.        if (ibyte_count <= 0)
  1562.       {
  1563.             /* Out of bytes in current block, so read next block */
  1564.           
  1565.             ibyte_ptr = ibyte_buff;
  1566.           
  1567.             if ((ibyte_count = iget_byte()) < 0) return(ibyte_count);
  1568.           else if (ibyte_count)
  1569.             {
  1570.                 for (i = 0; i < ibyte_count; ++i)
  1571.               {
  1572.                   if ((x = iget_byte()) < 0) return(x);
  1573.           
  1574.                     ibyte_buff[i] = (UTINY) x;
  1575.               }
  1576.             }
  1577.         }
  1578.         
  1579.         ibyte = *ibyte_ptr++;
  1580.         
  1581.         ret |= ibyte << ibit_count;
  1582.         
  1583.         ibit_count += 8;
  1584.         --ibyte_count;
  1585.     }
  1586.       
  1587.     ibit_count -= icurr_size;
  1588.       
  1589.     ret &= code_mask[icurr_size];
  1590.       
  1591.     return((WORD)(ret));
  1592. }
  1593.  
  1594.  
  1595. /*                                    */
  1596. /* Allocate stacks            */
  1597. /*                                    */
  1598.  
  1599. int ialloc_gif_stacks() 
  1600. {
  1601.     idstack = (UTINY *) malloc((MAX_CODES + 1)*sizeof(UTINY));
  1602.       isuffix = (UTINY *) malloc((MAX_CODES + 1)*sizeof(UTINY));
  1603.       iprefix = (UWORD *) malloc((MAX_CODES + 1)*sizeof(UWORD));
  1604.  
  1605.     return(0);
  1606. }
  1607.  
  1608.  
  1609. /*                                    */
  1610. /* Release stacks                */
  1611. /*                                    */
  1612.  
  1613. void ifree_gif_stacks() 
  1614. {
  1615.     free(idstack);
  1616.       free(isuffix);
  1617.       free(iprefix);
  1618. }
  1619.  
  1620. /*                                                        */
  1621. /* Initialize for decoding a new image    */
  1622. /*                                                        */
  1623.  
  1624. int    iinit_gif_decoder()
  1625. {
  1626.   int        i, ret;
  1627.  
  1628.  
  1629.   ret = 0;
  1630.   
  1631.   if ((icode_size = iget_byte()) < 0) return(icode_size);
  1632.  
  1633.   if (icode_size < 2 || 9 < icode_size) return(BAD_CODE_SIZE);
  1634.  
  1635.   icurr_size = icode_size + 1;
  1636.   
  1637.   itop_slot = 1 << icurr_size;
  1638.   
  1639.   iclear = 1 << icode_size;
  1640.   
  1641.   iending = iclear + 1;
  1642.   
  1643.   islot = inew_codes = iending + 1;
  1644.   
  1645.   ibyte_count = ibit_count = 0;
  1646.   
  1647.   /* Initialize in case they forgot to put in a clear code.                */
  1648.   /* (This shouldn't happen, but we'll try and decode it anyway...)    */
  1649.  
  1650.   iold_code = iout_value = 0;
  1651.  
  1652.   ibad_code_count = 0;
  1653.  
  1654.   /* Set up the stack pointer and decode buffer pointer */
  1655.  
  1656.   iemit_index = idstack;
  1657.  
  1658.   for(i=0; i<MAX_CODES+1; i++) iprefix[i] = 0;
  1659.   for(i=0; i<MAX_CODES+1; i++) isuffix[i] = 0;
  1660.  
  1661.   return(ret);
  1662. }
  1663.  
  1664.  
  1665. /*                                                    */
  1666. /* Get next byte from GIF decoder        */
  1667. /*                                                    */
  1668.  
  1669.  
  1670. int idecode_gif()
  1671.  
  1672. {
  1673.       register int    c;
  1674.     register int    code;
  1675.  
  1676.       /* This is the main loop.  For each code we get we pass through the
  1677.     * linked list of iprefix codes, pushing the corresponding "character" for
  1678.     * each code onto the stack.  When the list reaches a single "character"
  1679.     * we push that on the stack too, and then start unstacking each
  1680.     * character for output in the correct order.  Special handling is
  1681.     * included for the clear code, and the whole thing ends when we get
  1682.     * an ending code.
  1683.     */
  1684.  
  1685.    if(iemit_index > idstack) return(*(--iemit_index));
  1686.  
  1687.     while ((c = iget_next_code()) != iending)
  1688.    {
  1689.        /* If we had a file error, return without completing the decode    */
  1690.  
  1691.         if(c < 0) 
  1692.         return(0);
  1693.  
  1694.         /* If the code is a clear code, reinitialize all necessary items    */
  1695.  
  1696.         if(c == iclear)
  1697.       {
  1698.           icurr_size = icode_size + 1;
  1699.           islot = inew_codes;
  1700.           itop_slot = 1 << icurr_size;
  1701.  
  1702.           /* Continue reading codes until we get a non-clear code */
  1703.          /* (Another unlikely, but possible case...)                  */
  1704.  
  1705.             while ((c = iget_next_code()) == iclear);
  1706.  
  1707.           /* If we get an ending code immediately after a clear code    */
  1708.          /* (Yet another unlikely case), then break out of the loop.    */
  1709.  
  1710.             if(c == iending) break;
  1711.  
  1712.             /* Finally, if the code is beyond the range of already set            */
  1713.             /* codes, (This one had better NOT happen...  I have no idea         */
  1714.             /*    what will result from this, but I doubt it will look good...     */
  1715.             /* then set it    to color zero                                                    */
  1716.  
  1717.             if(c >= islot) c = 0;
  1718.  
  1719.           iold_code = iout_value = c;
  1720.  
  1721.           /* And let us not forget to put the character into the buffer        */
  1722.  
  1723.             return(c);
  1724.         }
  1725.         else
  1726.         {
  1727.              /* In this case, it's not a clear code or an ending code, so            */
  1728.           /* it must be a code code...  So we can now decode the code into        */
  1729.           /* a stack of character codes. (Clear as mud, right?)                        */
  1730.  
  1731.             code = c;
  1732.  
  1733.           /* Here we go again with one of those off chances...  If, on the        */
  1734.           /* off chance, the code we got is beyond the range of those already    */
  1735.           /* set up (Another thing which had better NOT happen...) we trick        */
  1736.           /* the decoder into thinking it actually got the last code read.        */
  1737.           /* (Hmmn... I'm not sure why this works...  But it does...)                */
  1738.  
  1739.             if(code >= islot)
  1740.             {
  1741.               if(code > islot) ++ibad_code_count;
  1742.                 code = iold_code;
  1743.                 *iemit_index++ = (UTINY) iout_value;
  1744.           }
  1745.  
  1746.           /* Here we scan back along the linked list of iprefixes, pushing        */
  1747.              /* helpless characters (ie. isuffixes) onto the stack as we do so.        */
  1748.        
  1749.           while (code >= inew_codes)
  1750.           {
  1751.               *iemit_index++ = isuffix[code];
  1752.                 code = iprefix[code];
  1753.           }
  1754.  
  1755.           /* Push the last character on the stack, and set up the new                */
  1756.           /* iprefix and isuffix, and if the required slot number is greater        */
  1757.           /* than that allowed by the current bit size, increase the bit            */
  1758.           /* size.  (NOTE - If we are all full, we *don't* save the new            */
  1759.           /* isuffix and iprefix...  I'm not certain if this is correct...            */
  1760.           /* it might be more proper to overwrite the last code...                    */
  1761.  
  1762.           *iemit_index++ = (UTINY) code;
  1763.  
  1764.             if(islot < itop_slot)
  1765.           {
  1766.               iout_value = code;
  1767.                 isuffix[islot] = (UTINY) iout_value;
  1768.                 iprefix[islot++] = iold_code;
  1769.                 iold_code = c;
  1770.           }
  1771.           
  1772.             if(islot >= itop_slot)
  1773.             {
  1774.                 if(icurr_size < 12)
  1775.              {
  1776.                  itop_slot <<= 1;
  1777.                   ++icurr_size;
  1778.              }
  1779.             }
  1780.  
  1781.           /* Now that we've pushed the decoded string (in reverse order)            */
  1782.           /* onto the stack, lets pop it off and return it a byte at a             */
  1783.           /* time to the caller                                                                */
  1784.        
  1785.           if(iemit_index > idstack) return(*(--iemit_index));
  1786.         }
  1787.     }
  1788.     return(c);
  1789. }
  1790.  
  1791.  
  1792. /*                                                        */
  1793. /* Get next byte of input for GIF decoder    */
  1794. /*                                                     */
  1795.  
  1796. int bget_byte()
  1797. {
  1798.     int    b;
  1799.     
  1800.     if((b = fgetc(bfile)) != EOF) return(b);
  1801.  
  1802.     printf("Premature EOF in GIF background file %s\n", bname);
  1803.  
  1804.     return(b);
  1805. }
  1806.  
  1807. /*                                                                      */
  1808. /* get the next code from the background GIF file    */
  1809. /*                                                                    */
  1810.  
  1811. WORD bget_next_code()
  1812.   {
  1813.       WORD i, x;
  1814.  
  1815.       ULONG ret;
  1816.  
  1817.     if (bbit_count == 0)
  1818.       {
  1819.           if (bbyte_count <= 0)
  1820.        {
  1821.             /* Out of bytes in current block, so read next block */
  1822.  
  1823.           bbyte_ptr = bbyte_buff;
  1824.       
  1825.             if ((bbyte_count = bget_byte()) < 0) return(bbyte_count);
  1826.           else if (bbyte_count)
  1827.           {        
  1828.               for (i = 0; i < bbyte_count; ++i)
  1829.              {
  1830.                  if ((x = bget_byte()) < 0) return(x);
  1831.               
  1832.                     bbyte_buff[i] = (UTINY) x;
  1833.                 }
  1834.           }
  1835.       }
  1836.         bbyte = *bbyte_ptr++;
  1837.     
  1838.         bbit_count = 8;
  1839.         --bbyte_count;
  1840.     }
  1841.  
  1842.       ret = bbyte >> (8 - bbit_count);
  1843.       
  1844.     while (bcurr_size > bbit_count)
  1845.    {
  1846.        if (bbyte_count <= 0)
  1847.       {
  1848.             /* Out of bytes in current block, so read next block */
  1849.           
  1850.             bbyte_ptr = bbyte_buff;
  1851.           
  1852.             if ((bbyte_count = bget_byte()) < 0) return(bbyte_count);
  1853.           else if (bbyte_count)
  1854.             {
  1855.                 for (i = 0; i < bbyte_count; ++i)
  1856.               {
  1857.                   if ((x = bget_byte()) < 0) return(x);
  1858.           
  1859.                     bbyte_buff[i] = (UTINY) x;
  1860.               }
  1861.             }
  1862.         }
  1863.         
  1864.         bbyte = *bbyte_ptr++;
  1865.         
  1866.         ret |= bbyte << bbit_count;
  1867.         
  1868.         bbit_count += 8;
  1869.         --bbyte_count;
  1870.     }
  1871.       
  1872.     bbit_count -= bcurr_size;
  1873.       
  1874.     ret &= code_mask[bcurr_size];
  1875.       
  1876.     return((WORD)(ret));
  1877. }
  1878.  
  1879.  
  1880. /*                                    */
  1881. /* Allocate stacks            */
  1882. /*                                    */
  1883.  
  1884. int balloc_gif_stacks() 
  1885. {
  1886.     bdstack = (UTINY *) malloc((MAX_CODES + 1)*sizeof(UTINY));
  1887.       bsuffix = (UTINY *) malloc((MAX_CODES + 1)*sizeof(UTINY));
  1888.       bprefix = (UWORD *) malloc((MAX_CODES + 1)*sizeof(UWORD));
  1889.  
  1890.     return(0);
  1891. }
  1892.  
  1893.  
  1894. /*                                    */
  1895. /* Release stacks                */
  1896. /*                                    */
  1897.  
  1898. void bfree_gif_stacks() 
  1899. {
  1900.     free(bdstack);
  1901.       free(bsuffix);
  1902.       free(bprefix);
  1903. }
  1904.  
  1905. /*                                                        */
  1906. /* Initialize for decoding a new image    */
  1907. /*                                                        */
  1908.  
  1909. int    binit_gif_decoder()
  1910. {
  1911.   int        i, ret;
  1912.  
  1913.  
  1914.   ret = 0;
  1915.   
  1916.   if ((bcode_size = bget_byte()) < 0) return(bcode_size);
  1917.  
  1918.   if (bcode_size < 2 || 9 < bcode_size) return(BAD_CODE_SIZE);
  1919.  
  1920.   bcurr_size = bcode_size + 1;
  1921.   
  1922.   btop_slot = 1 << bcurr_size;
  1923.   
  1924.   bclear = 1 << bcode_size;
  1925.   
  1926.   bending = bclear + 1;
  1927.   
  1928.   bslot = bnew_codes = bending + 1;
  1929.   
  1930.   bbyte_count = bbit_count = 0;
  1931.   
  1932.   /* Initialize in case they forgot to put in a clear code.                */
  1933.   /* (This shouldn't happen, but we'll try and decode it anyway...)    */
  1934.  
  1935.   bold_code = bout_value = 0;
  1936.  
  1937.   bbad_code_count = 0;
  1938.  
  1939.   /* Set up the stack pointer and decode buffer pointer */
  1940.  
  1941.   bemit_index = bdstack;
  1942.  
  1943.   for(i=0; i<MAX_CODES+1; i++) bprefix[i] = 0;
  1944.   for(i=0; i<MAX_CODES+1; i++) bsuffix[i] = 0;
  1945.  
  1946.   return(ret);
  1947. }
  1948.  
  1949.  
  1950. /*                                                    */
  1951. /* Get next byte from GIF decoder        */
  1952. /*                                                    */
  1953.  
  1954.  
  1955. int bdecode_gif()
  1956.  
  1957. {
  1958.       register int    c;
  1959.     register int    code;
  1960.  
  1961.       /* This is the main loop.  For each code we get we pass through the
  1962.     * linked list of iprefix codes, pushing the corresponding "character" for
  1963.     * each code onto the stack.  When the list reaches a single "character"
  1964.     * we push that on the stack too, and then start unstacking each
  1965.     * character for output in the correct order.  Special handling is
  1966.     * included for the clear code, and the whole thing ends when we get
  1967.     * an ending code.
  1968.     */
  1969.  
  1970.    if(bemit_index > bdstack) return(*(--bemit_index));
  1971.  
  1972.     while ((c = bget_next_code()) != bending)
  1973.    {
  1974.        /* If we had a file error, return without completing the decode    */
  1975.  
  1976.         if(c < 0) 
  1977.         return(0);
  1978.  
  1979.         /* If the code is a clear code, reinitialize all necessary items    */
  1980.  
  1981.         if(c == bclear)
  1982.       {
  1983.           bcurr_size = bcode_size + 1;
  1984.           bslot = bnew_codes;
  1985.           btop_slot = 1 << bcurr_size;
  1986.  
  1987.           /* Continue reading codes until we get a non-clear code */
  1988.          /* (Another unlikely, but possible case...)                  */
  1989.  
  1990.             while ((c = bget_next_code()) == bclear);
  1991.  
  1992.           /* If we get an ending code immediately after a clear code    */
  1993.          /* (Yet another unlikely case), then break out of the loop.    */
  1994.  
  1995.             if(c == bending) break;
  1996.  
  1997.             /* Finally, if the code is beyond the range of already set            */
  1998.             /* codes, (This one had better NOT happen...  I have no idea         */
  1999.             /*    what will result from this, but I doubt it will look good...     */
  2000.             /* then set it    to color zero                                                    */
  2001.  
  2002.             if(c >= bslot) c = 0;
  2003.  
  2004.           bold_code = bout_value = c;
  2005.  
  2006.           /* And let us not forget to put the character into the buffer        */
  2007.  
  2008.             return(c);
  2009.         }
  2010.         else
  2011.         {
  2012.              /* In this case, it's not a clear code or an ending code, so            */
  2013.           /* it must be a code code...  So we can now decode the code into        */
  2014.           /* a stack of character codes. (Clear as mud, right?)                        */
  2015.  
  2016.             code = c;
  2017.  
  2018.           /* Here we go again with one of those off chances...  If, on the        */
  2019.           /* off chance, the code we got is beyond the range of those already    */
  2020.           /* set up (Another thing which had better NOT happen...) we trick        */
  2021.           /* the decoder into thinking it actually got the last code read.        */
  2022.           /* (Hmmn... I'm not sure why this works...  But it does...)                */
  2023.  
  2024.             if(code >= bslot)
  2025.             {
  2026.               if(code > bslot) ++bbad_code_count;
  2027.                 code = bold_code;
  2028.                 *bemit_index++ = (UTINY) bout_value;
  2029.           }
  2030.  
  2031.           /* Here we scan back along the linked list of iprefixes, pushing        */
  2032.              /* helpless characters (ie. isuffixes) onto the stack as we do so.        */
  2033.        
  2034.           while (code >= bnew_codes)
  2035.           {
  2036.               *bemit_index++ = bsuffix[code];
  2037.                 code = bprefix[code];
  2038.           }
  2039.  
  2040.           /* Push the last character on the stack, and set up the new                */
  2041.           /* iprefix and isuffix, and if the required slot number is greater        */
  2042.           /* than that allowed by the current bit size, increase the bit            */
  2043.           /* size.  (NOTE - If we are all full, we *don't* save the new            */
  2044.           /* isuffix and iprefix...  I'm not certain if this is correct...            */
  2045.           /* it might be more proper to overwrite the last code...                    */
  2046.  
  2047.           *bemit_index++ = (UTINY) code;
  2048.  
  2049.             if(bslot < btop_slot)
  2050.           {
  2051.               bout_value = code;
  2052.                 bsuffix[bslot] = (UTINY) bout_value;
  2053.                 bprefix[bslot++] = bold_code;
  2054.                 bold_code = c;
  2055.           }
  2056.           
  2057.             if(bslot >= btop_slot)
  2058.             {
  2059.                 if(bcurr_size < 12)
  2060.              {
  2061.                  btop_slot <<= 1;
  2062.                   ++bcurr_size;
  2063.              }
  2064.             }
  2065.  
  2066.           /* Now that we've pushed the decoded string (in reverse order)            */
  2067.           /* onto the stack, lets pop it off and return it a byte at a             */
  2068.           /* time to the caller                                                                */
  2069.        
  2070.           if(bemit_index > bdstack) return(*(--bemit_index));
  2071.         }
  2072.     }
  2073.     return(c);
  2074. }
  2075.  
  2076.  
  2077. /******************************************************************************
  2078.  *
  2079.  * GIF output routines
  2080.  *
  2081.  ******************************************************************************/
  2082.  
  2083. /*    Number of characters so far in this 'packet' */
  2084.  
  2085. static int a_count;
  2086.  
  2087.  
  2088. /*    Set up the 'byte output' routine */
  2089.  
  2090. void char_init()
  2091. {
  2092.     a_count = 0;
  2093. }
  2094.  
  2095. /*    Define the storage for the packet accumulator */
  2096.  
  2097. static char accum[ 256 ];
  2098.  
  2099. /*
  2100.  * Add a character to the end of the current packet, and if it is 254
  2101.  * characters, flush the packet to disk.
  2102.  */
  2103.  
  2104. void char_out( c )
  2105. int c;
  2106. {
  2107.     accum[ a_count++ ] = c;
  2108.     if( a_count >= 254 )
  2109.         flush_char();
  2110. }
  2111.  
  2112. /*
  2113.  * Flush the packet to disk, and reset the accumulator
  2114.  */
  2115.  
  2116. void    flush_char()
  2117. {
  2118.     if( a_count > 0 ) {
  2119.         fputc( a_count, g_outfile );
  2120.         fwrite( accum, 1, a_count, g_outfile );
  2121.         a_count = 0;
  2122.     }
  2123. }
  2124.  
  2125.  
  2126. /*                                                    */
  2127. /* Write out a word to the GIF file        */
  2128. /*                                                    */
  2129.  
  2130. void Putword(int w, FILE *fp )
  2131. {
  2132.     fputc( w & 0xff, fp );
  2133.     fputc( (w / 256) & 0xff, fp );
  2134. }
  2135.  
  2136. /*
  2137.  * Bump the 'curx' and 'cury' to point to the next pixel
  2138.  */
  2139.  
  2140. static void BumpPixel()
  2141. {
  2142.     /*
  2143.      * Bump the current X position
  2144.      */
  2145.     curx++;
  2146.  
  2147.     /*
  2148.      * If we are at the end of a scan line, set curx back to the beginning
  2149.      * If we are interlaced, bump the cury to the appropriate spot,
  2150.      * otherwise, just increment it.
  2151.      */
  2152.     if( curx == Width ) {
  2153.         curx = 0;
  2154.  
  2155.             if( !Interlace )
  2156.             cury++;
  2157.         else {
  2158.              switch( Pass ) {
  2159.  
  2160.                    case 0:
  2161.                       cury += 8;
  2162.                       if( cury >= Height ) {
  2163.                   Pass++;
  2164.                 cury = 4;
  2165.                 }
  2166.                           break;
  2167.  
  2168.                    case 1:
  2169.                       cury += 8;
  2170.                       if( cury >= Height ) {
  2171.                   Pass++;
  2172.                 cury = 2;
  2173.                 }
  2174.               break;
  2175.  
  2176.                    case 2:
  2177.                       cury += 4;
  2178.                       if( cury >= Height ) {
  2179.                          Pass++;
  2180.                          cury = 1;
  2181.                       }
  2182.                       break;
  2183.  
  2184.                    case 3:
  2185.                       cury += 2;
  2186.                       break;
  2187.             }
  2188.         }
  2189.     }
  2190. }
  2191.  
  2192. /*
  2193.  * Return the next pixel from the image
  2194.  */
  2195.  
  2196. int GIFNextPixel(getpixel)
  2197. ifunptr getpixel;
  2198. {
  2199.     int r;
  2200.  
  2201.     if( CountDown == 0 )
  2202.         return EOF;
  2203.  
  2204.     CountDown--;
  2205.  
  2206.     r = getpixel( curx, cury );
  2207.  
  2208.     BumpPixel();
  2209.  
  2210.     return r;
  2211. }
  2212.  
  2213. /* public */
  2214.  
  2215. void GIFEncode( FName, GWidth, GHeight, GInterlace, Background,
  2216.                     BitsPerPixel, Red, Green, Blue, GetPixel )
  2217.  
  2218. char *    FName;
  2219. int         GWidth, GHeight;
  2220. int         GInterlace;
  2221. int         Background;
  2222. int         BitsPerPixel;
  2223. int         Red[], Green[], Blue[];
  2224. ifunptr     GetPixel;
  2225.  
  2226. {
  2227.     FILE *fp;
  2228.     int B;
  2229.     int RWidth, RHeight;
  2230.     int LeftOfs, TopOfs;
  2231.     int Resolution;
  2232.     int ColorMapSize;
  2233.     int InitCodeSize;
  2234.     int i;
  2235.  
  2236.     Interlace = GInterlace;
  2237.  
  2238.     ColorMapSize = 1 << BitsPerPixel;
  2239.  
  2240.     RWidth = Width = GWidth;
  2241.     RHeight = Height = GHeight;
  2242.     LeftOfs = TopOfs = 0;
  2243.  
  2244.     Resolution = BitsPerPixel;
  2245.  
  2246.     /*
  2247.      * Calculate number of bits we are expecting
  2248.      */
  2249.     CountDown = (long)Width * (long)Height;
  2250.  
  2251.     /*
  2252.      * Indicate which pass we are on (if interlace)
  2253.      */
  2254.     Pass = 0;
  2255.  
  2256.     /*
  2257.      * The initial code size
  2258.      */
  2259.     if( BitsPerPixel <= 1 )
  2260.         InitCodeSize = 2;
  2261.     else
  2262.         InitCodeSize = BitsPerPixel;
  2263.  
  2264.     /*
  2265.      * Set up the current x and y position
  2266.      */
  2267.     curx = cury = 0;
  2268.  
  2269.     /*
  2270.      * Open the GIF file for binary write
  2271.      */
  2272.     fp = fopen( FName, "wb" );
  2273.  
  2274.     if( fp == (FILE *)0 ) {
  2275.         printf( "error: could not open output file\n" );
  2276.         exit(1);
  2277.     }
  2278.  
  2279.     /*
  2280.      * Write the Magic header
  2281.      */
  2282.     fwrite( "GIF87a", 1, 6, fp );
  2283.  
  2284.     /*
  2285.      * Write out the screen width and height
  2286.      */
  2287.     Putword( RWidth, fp );
  2288.     Putword( RHeight, fp );
  2289.  
  2290.     /*
  2291.      * Indicate that there is a global colour map
  2292.      */
  2293.     B = 0x80;    /* Yes, there is a color map */
  2294.  
  2295.     /*
  2296.      * OR in the resolution
  2297.      */
  2298.     B |= (Resolution - 1) << 5;
  2299.  
  2300.     /*
  2301.      * OR in the Bits per Pixel
  2302.      */
  2303.     B |= (BitsPerPixel - 1);
  2304.  
  2305.     /*
  2306.      * Write it out
  2307.      */
  2308.     fputc( B, fp );
  2309.  
  2310.     /*
  2311.      * Write out the Background colour
  2312.      */
  2313.     fputc( Background, fp );
  2314.  
  2315.     /*
  2316.      * Byte of 0's (future expansion)
  2317.      */
  2318.     fputc( 0, fp );
  2319.  
  2320.     /*
  2321.      * Write out the Global Colour Map
  2322.      */
  2323.          for( i=0; i<ColorMapSize; i++ ) {
  2324.         fputc( Red[i], fp );
  2325.         fputc( Green[i], fp );
  2326.         fputc( Blue[i], fp );
  2327.     }
  2328.  
  2329.     /*
  2330.      * Write an Image separator
  2331.      */
  2332.     fputc( ',', fp );
  2333.  
  2334.     /*
  2335.      * Write the Image header
  2336.      */
  2337.  
  2338.     Putword( LeftOfs, fp );
  2339.     Putword( TopOfs, fp );
  2340.     Putword( Width, fp );
  2341.     Putword( Height, fp );
  2342.  
  2343.     /*
  2344.      * Write out whether or not the image is interlaced
  2345.      */
  2346.     if( Interlace )
  2347.         fputc( 0x40, fp );
  2348.     else
  2349.         fputc( 0x00, fp );
  2350.  
  2351.     /*
  2352.      * Write out the initial code size
  2353.      */
  2354.     fputc( InitCodeSize, fp );
  2355.  
  2356.     /*
  2357.      * Go and actually compress the data
  2358.      */
  2359.     compress( InitCodeSize+1, fp, GetPixel );
  2360.  
  2361.     /*
  2362.      * Write out a Zero-length packet (to end the series)
  2363.      */
  2364.     fputc( 0, fp );
  2365.  
  2366.     /*
  2367.      * Write the GIF file terminator
  2368.      */
  2369.     fputc( ';', fp );
  2370.  
  2371.     /*
  2372.      * And close the file
  2373.      */
  2374.     fclose(fp);
  2375.  
  2376. }
  2377.  
  2378. /*                                                                                                    */
  2379. /*    GIF encoding routine                                                                        */
  2380. /*                                                                                                    */
  2381. /* This routine was borrowed from TGA2GIF with very little modification     */
  2382. /*    I must give credit to the original authors for their highly useful code */
  2383. /*                                                                                                    */
  2384. /* Based on :        GIFENCODE.C - An LZW encoder for GIF                            */
  2385. /*                        Written by Steven B. Coy                                            */
  2386. /*                        From code by David Rowley                                            */
  2387. /*                        And modified by Drew Wells and Chris Cason                    */
  2388. /*                                                                                                 */
  2389. /*
  2390.  * GIF Image compression - modified 'compress'
  2391.  *
  2392.  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
  2393.  *
  2394.  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
  2395.  *              Jim McKie               (decvax!mcvax!jim)
  2396.  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
  2397.  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
  2398.  *              James A. Woods          (decvax!ihnp4!ames!jaw)
  2399.  *              Joe Orost               (decvax!vax135!petsd!joe)
  2400.  *
  2401.  */
  2402.  
  2403. /*
  2404.  * compress stdin to stdout
  2405.  *
  2406.  * Algorithm:  use open addressing double hashing (no chaining) on the
  2407.  * iprefix code / next character combination.  We do a variant of Knuth's
  2408.  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
  2409.  * secondary probe.  Here, the modular division first probe is gives way
  2410.  * to a faster exclusive-or manipulation.  Also do block compression with
  2411.  * an adaptive reset, whereby the code table is cleared when the compression
  2412.  * ratio decreases, but after the table fills.  The variable-length output
  2413.  * codes are re-sized at this point, and a special CLEAR code is generated
  2414.  * for the decompressor.  Late addition:  construct the table according to
  2415.  * file size for noticeable speed improvement on small files.  Please direct
  2416.  * questions about this implementation to ames!jaw.
  2417.  */
  2418.  
  2419. compress( init_bits, outfile, ReadValue )
  2420. int init_bits;
  2421. FILE *outfile;
  2422. ifunptr ReadValue;
  2423. {
  2424.     register long fcode;
  2425.     register code_int i = 0;
  2426.     register int c;
  2427.     register code_int ent;
  2428.     register code_int disp;
  2429.     register code_int hsize_reg;
  2430.     register int hshift;
  2431.  
  2432.     /*
  2433.      * Set up the globals:  g_init_bits - initial number of bits
  2434.      *                      g_outfile   - pointer to output file
  2435.      */
  2436.     g_init_bits = init_bits;
  2437.     g_outfile = outfile;
  2438.  
  2439.     /*
  2440.      * Set up the necessary values
  2441.      */
  2442.     offset = 0;
  2443.     out_count = 0;
  2444.     clear_flg = 0;
  2445.     in_count = 1;
  2446.     maxcode = MAXCODE(n_bits = g_init_bits);
  2447.  
  2448.     ClearCode = (1 << (init_bits - 1));
  2449.     EOFCode = ClearCode + 1;
  2450.     free_ent = ClearCode + 2;
  2451.  
  2452.     char_init();
  2453.  
  2454.     ent = GIFNextPixel( ReadValue );
  2455.  
  2456.     hshift = 0;
  2457.     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
  2458.     hshift++;
  2459.     hshift = 8 - hshift;                /* set hash code range bound */
  2460.  
  2461.     hsize_reg = hsize;
  2462.     cl_hash( (count_int) hsize_reg);            /* clear hash table */
  2463.  
  2464.     output( (code_int)ClearCode );
  2465.  
  2466. #ifdef SIGNED_COMPARE_SLOW
  2467.     while ( (c = GIFNextPixel( ReadValue )) != (unsigned) EOF ) {
  2468. #else
  2469.     while ( (c = GIFNextPixel( ReadValue )) != EOF ) {
  2470. #endif
  2471.  
  2472.     in_count++;
  2473.  
  2474.     fcode = (long) (((long) c << maxbits) + ent);
  2475.     i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
  2476.  
  2477.     if ( HashTabOf (i) == fcode ) {
  2478.         ent = CodeTabOf (i);
  2479.         continue;
  2480.     } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
  2481.         goto nomatch;
  2482.     disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
  2483.     if ( i == 0 )
  2484.         disp = 1;
  2485. probe:
  2486.     if ( (i -= disp) < 0 )
  2487.         i += hsize_reg;
  2488.  
  2489.     if ( HashTabOf (i) == fcode ) {
  2490.         ent = CodeTabOf (i);
  2491.         continue;
  2492.     }
  2493.     if ( (long)HashTabOf (i) > 0 )
  2494.         goto probe;
  2495. nomatch:
  2496.     output ( (code_int) ent );
  2497.     out_count++;
  2498.     ent = c;
  2499. #ifdef SIGNED_COMPARE_SLOW
  2500.     if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
  2501. #else
  2502.     if ( free_ent < maxmaxcode ) {
  2503. #endif
  2504.         CodeTabOf (i) = free_ent++; /* code -> hashtable */
  2505.         HashTabOf (i) = fcode;
  2506.     } else
  2507.         cl_block();
  2508.     }
  2509.     /*
  2510.      * Put out the final code.
  2511.      */
  2512.     output( (code_int)ent );
  2513.     out_count++;
  2514.     output( (code_int) EOFCode );
  2515.  
  2516.     return 0;
  2517. }
  2518.  
  2519. /*****************************************************************
  2520.  * TAG( output )
  2521.  *
  2522.  * Output the given code.
  2523.  * Inputs:
  2524.  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
  2525.  *              that n_bits =< (long)wordsize - 1.
  2526.  * Outputs:
  2527.  *      Outputs code to the file.
  2528.  * Assumptions:
  2529.  *      Chars are 8 bits long.
  2530.  * Algorithm:
  2531.  *      Maintain a BITS character long buffer (so that 8 codes will
  2532.  * fit in it exactly).  Use the VAX insv instruction to insert each
  2533.  * code in turn.  When the buffer fills up empty it and start over.
  2534.  */
  2535.  
  2536. void    output( code )
  2537. code_int  code;
  2538. {
  2539.     cur_accum &= code_mask[ cur_bits ];
  2540.  
  2541.     if( cur_bits > 0 )
  2542.     cur_accum |= ((long)code << cur_bits);
  2543.     else
  2544.     cur_accum = code;
  2545.  
  2546.     cur_bits += n_bits;
  2547.  
  2548.     while( cur_bits >= 8 ) {
  2549.     char_out( (unsigned int)(cur_accum & 0xff) );
  2550.     cur_accum >>= 8;
  2551.     cur_bits -= 8;
  2552.     }
  2553.  
  2554.     /*
  2555.      * If the next entry is going to be too big for the code size,
  2556.      * then increase it, if possible.
  2557.      */
  2558.    if ( free_ent > maxcode || clear_flg ) {
  2559.  
  2560.         if( clear_flg ) {
  2561.  
  2562.         maxcode = MAXCODE (n_bits = g_init_bits);
  2563.         clear_flg = 0;
  2564.  
  2565.         } else {
  2566.  
  2567.         n_bits++;
  2568.         if ( n_bits == maxbits )
  2569.             maxcode = maxmaxcode;
  2570.         else
  2571.             maxcode = MAXCODE(n_bits);
  2572.         }
  2573.     }
  2574.  
  2575.     if( code == EOFCode ) {
  2576.     /*
  2577.      * At EOF, write the rest of the buffer.
  2578.      */
  2579.     while( cur_bits > 0 ) {
  2580.         char_out( (unsigned int)(cur_accum & 0xff) );
  2581.         cur_accum >>= 8;
  2582.         cur_bits -= 8;
  2583.     }
  2584.  
  2585.     flush_char();
  2586.  
  2587.     fflush( g_outfile );
  2588.  
  2589.     if( ferror( g_outfile ) )
  2590.         writeerr();
  2591.     }
  2592. }
  2593.  
  2594. /*
  2595.  * Clear out the hash table
  2596.  */
  2597.  
  2598. void    cl_block ()             /* table clear for block compress */
  2599. {
  2600.  
  2601.     cl_hash ( (count_int) hsize );
  2602.     free_ent = ClearCode + 2;
  2603.     clear_flg = 1;
  2604.  
  2605.     output( (code_int)ClearCode );
  2606. }
  2607.  
  2608. void    cl_hash(hsize)          /* reset code table */
  2609. register count_int hsize;
  2610. {
  2611.  
  2612.     register count_int *htab_p = htab+hsize;
  2613.  
  2614.     register long i;
  2615.     register long m1 = -1;
  2616.  
  2617.     i = hsize - 16;
  2618.     do {                            /* might use Sys V memset(3) here */
  2619.         *(htab_p-16) = m1;
  2620.         *(htab_p-15) = m1;
  2621.         *(htab_p-14) = m1;
  2622.         *(htab_p-13) = m1;
  2623.         *(htab_p-12) = m1;
  2624.         *(htab_p-11) = m1;
  2625.         *(htab_p-10) = m1;
  2626.         *(htab_p-9) = m1;
  2627.         *(htab_p-8) = m1;
  2628.         *(htab_p-7) = m1;
  2629.         *(htab_p-6) = m1;
  2630.         *(htab_p-5) = m1;
  2631.         *(htab_p-4) = m1;
  2632.         *(htab_p-3) = m1;
  2633.         *(htab_p-2) = m1;
  2634.         *(htab_p-1) = m1;
  2635.         htab_p -= 16;
  2636.     } while ((i -= 16) >= 0);
  2637.  
  2638.     for ( i += 16; i > 0; i-- )
  2639.         *--htab_p = m1;
  2640. }
  2641.  
  2642. void    writeerr()
  2643. {
  2644.     printf( "error writing output file\n" );
  2645.     exit(1);
  2646. }
  2647.  
  2648.  
  2649.  
  2650.