home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1988 / 11 / duvanenk.asc next >
Text File  |  1988-10-21  |  31KB  |  738 lines

  1. _IMAGE COMPRESSION VIA COMPILATION_
  2. by
  3. Victor J. Duvanenko
  4.  
  5.  
  6. [LISTING ONE]
  7.  
  8.  
  9. /*               Bitmap compaction program.                                 */
  10. /* Converts bitmaps in 82786 graphics memory to Graphics processor instruc- */
  11. /* tions. Simulates run length encoding, causing data compression for most  */
  12. /* bitmaps. Compression of an 8 bits per pixel down to 3 bits per pixel is  */
  13. /* not uncommon.                                                            */
  14. /*         Created by Victor J. Duvanenko                                   */
  15. /* Usage:          compact output_file_name                                 */
  16. /* Input:                                                                   */
  17. /*        An 82786 eight bits per pixel bitmap at address of 0x10000 (this  */
  18. /*        can be easily changed). The bitmap is 640 pixels wide and 480     */
  19. /*        pixels heigh (this can also be changed). This was done for the    */
  20. /*        simplicity of this example.                                       */
  21. /* Output:                                                                  */
  22. /*        Binary file in the following format.                              */
  23. /*        a) Header                                                         */
  24. /*           1) type ( 0 - GP instructions, 1 - bitmap data ).              */
  25. /*           2) 32 bit address (lets the loader know where to place the     */
  26. /*              data in graphics/82786 memory). If equal to 0xffffffff      */
  27. /*              then the loader can place data anywhere.                    */
  28. /*           3) number of bytes to load.                                    */
  29. /*        b) Data                                                           */
  30. /*           1) define color instruction                                    */
  31. /*           2) scan line instruction                                       */
  32. /*           3) link instruction (link around the array)                    */
  33. /*           4) scan line array                                             */
  34. /*        Caution: The loader must add a 'stop' instruction to the data     */
  35. /*                 (a NOP instruction with GCL bit set). See loader source  */
  36. /*                 code for example.                                        */
  37. /*                                                                          */
  38. /* This program was written for the XENIX environment, but can be easily    */
  39. /* and quickly ported to the PC. Just concentrate on the ideas and not on   */
  40. /* the implementation specifics. I'll try to point out XENIX specific sec-  */
  41. /* tions.                                                                   */
  42.  
  43. #include<stdio.h>
  44. #include<fcntl.h> 
  45. #include<sys/param.h>
  46. #include "/usr/tls786/h/tls786.h"
  47. #include "/usr/tls786/h/tv1786.h"
  48.  
  49. #defineMAX_NUM_COLORS  256     /* maximum number of colors   */
  50. #define GP_BUFF_SIZE   8192     /* GP instruction buffer size */
  51. #define     BITMAP_WIDTH    640
  52. #define TRUE              1
  53. #define FALSE             0
  54. #define OK             TRUE     /* return status for procedures           */
  55. #define PMODE          0644     /* protection mode of the output file     */
  56. #define MOVSW_ON       TRUE     /* enable 'move strings' in XENIX driver  */
  57. #define DEBUG         FALSE     /* top debug level - a fun one to turn on */
  58. #define DEBUG_1       FALSE     /* next debug level deeper                */
  59. #define DEBUG_2       FALSE     /* everything you'd ever care to trace    */
  60.  
  61. /* Global data buffers - used by several routines */
  62. unsigned int   gp_buff[ GP_BUFF_SIZE ];    /* GP instruction buffer    */
  63. unsigned int   buff[ GP_BUFF_SIZE ];       /* temporary storage buffer */
  64. unsigned char  line_buff[ BITMAP_WIDTH ];  /* line buffer              */
  65.             /* line_buff should ideally be dynamically alocated to allow any */
  66.             /* bitmap width. Left as an excersize for a C hacker.            */
  67.  
  68. int  p6handle;              /* XENIX file descriptor for the 82786 memory */
  69. int  bm_height  = 480;      /* bitmap height  */
  70. int  bm_width   = 640;      /* bitmap width   */
  71. long bm_address = 0x10000L; /* bitmap address */
  72.  
  73. /* Description of each color, histogram, plus additional fields for added  */
  74. /* dramatic performance improvement (defines a window of color existance). */
  75. /* Enable DEBUG to see time savings that result from this technique.       */
  76. struct  color_struct
  77. {
  78.   long  count;      /* number of times a color appears in the bitmap */
  79.   int   begin_y,    /* scan line  where a color first appears         */
  80.         end_y,      /* scan line  where a color last  appears         */
  81.         begin_x,    /* x position where a color first appears         */
  82.         end_x;      /* x position where a color last  appears         */
  83. };
  84. typedef struct  color_struct  color_t;
  85.  
  86. /* Array containing color information about a bitmap under analysis */
  87. color_t colors[ MAX_NUM_COLORS ];
  88.  
  89. /*------------------------------------------------------------------------*/
  90. /*             The body of the data compression program.                  */
  91. /*------------------------------------------------------------------------*/
  92. main(argc,argv)
  93. int argc;
  94. char *argv[];
  95. {
  96.     register i, index, j, num_colors;
  97.     int  n, value, x, y;
  98.     int  f1, f2,                        /* file descriptors */
  99.          buff_overflow;
  100.  
  101.      /* the following variables are for debug purposes only */
  102.      long     average_begin_y, average_end_y;
  103.      long     average_begin_x, average_end_x;
  104.      float     percentage_y, percentage_x;
  105.      color_t *clr_p;
  106.  
  107.      /* XENIX needed structures needed for movsw section of the driver */
  108.      union {
  109.              struct tv1_cntrl brddata;
  110.                byte   rawdata[ sizeof( struct tv1_cntrl ) ];
  111.             struct io_data      rdata;
  112.      } regdata;
  113.  
  114.   /* Check the command line for proper syntax, a little */
  115.   if (argc < 2)
  116.   {
  117.     fprintf( stderr,"Usage is: %s output_file_name\n", argv[0] );
  118.     exit(1);
  119.   }
  120.  
  121.   /* Open the file where compacted bitmap will be placed. If it doesn't */
  122.   /* exist create it.                                                   */
  123.   if (( f2 = open( argv[1], O_CREAT | O_WRONLY, PMODE ))  == -1 )
  124.   {
  125.      fprintf( stderr, "%s: Can't create %s.\n", argv[0], argv[1] );
  126.      exit(1);
  127.   }
  128.  
  129.   /* XENIX specific functions to allow one to treat 82786 graphics memory  */
  130.   /* as a file - a file descriptor gets passed to every routine that talks */
  131.   /* to the 82786. This allows a very flexible multiple 82786 environment. */
  132.   p6handle = open786( MASTER_786 );
  133.   if ( p6handle == NULL )     {
  134.      fprintf( stderr, "%s: Can't access 82786.\n", argv[0] );
  135.      exit(1);
  136.   }
  137.  
  138. #if MOVSW_ON
  139.   /* XENIX specific - enable movsw in the 82786 driver */
  140.   ioctl( p6handle, TEST_SFLAG, ®data );
  141.   if ( regdata.rdata.regval == FALSE )
  142.      ioctl( p6handle, SET_SFLAG, &value );
  143. #endif
  144.  
  145.   /* Find all unique colors in the bitmap file. */
  146.   num_colors = find_all_colors( colors, bm_height );
  147.  
  148. #if DEBUG
  149.   /* histogram and performance improvement information of the color */
  150.   /* existance window technique.                                    */
  151.   printf( "num_colors = %d\n", num_colors );
  152.   average_begin_y = average_end_y = 0L;
  153.   average_begin_x = average_end_x = 0L;
  154.   for( i = 0; i < MAX_NUM_COLORS; i++ )
  155.   {
  156.      clr_p = &colors[i];     /* for denser and cleaner notation purposes */
  157.      printf( "c %4d %7ld  b_y%4d  e_y%4d", i, clr_p->count, clr_p->begin_y,
  158.                                              clr_p->end_y );
  159.      printf( "  b_x%5d  e_x%5d\n", clr_p->begin_x, clr_p->end_x );
  160.  
  161.      /* average only the existing colors */
  162.      if ( clr_p->count != 0 )
  163.      {
  164.           average_begin_y += (long)clr_p->begin_y;
  165.           average_end_y   += (long)clr_p->end_y;
  166.           average_begin_x += (long)clr_p->begin_x;
  167.           average_end_x   += (long)clr_p->end_x;
  168.      }
  169.   }
  170.   printf( "\n" );
  171.   average_begin_y /= (long)num_colors;
  172.   average_end_y   /= (long)num_colors;
  173.   printf( "average Y begin = %ld\t\taverage Y end = %ld\n", average_begin_y,
  174.                                                            average_end_y   );
  175.   percentage_y  = ((float)( average_begin_y ) / bm_height * 100 );
  176.   percentage_y += ((float)((long)( bm_height ) - average_end_y ) / bm_height
  177.                    * 100 );
  178.   printf( "percentage Y savings = %2.2f\n", percentage_y );
  179.  
  180.   average_begin_x /= (long)num_colors;
  181.   average_end_x   /= (long)num_colors;
  182.   printf( "average X begin = %ld\t\taverage X end = %ld\n", average_begin_x,
  183.                                                             average_end_x   );
  184.   percentage_x  = ((float)( average_begin_x ) / bm_width * 100 );
  185.   percentage_x += ((float)((long)( bm_width ) - average_end_x ) / bm_width
  186.                    * 100 );
  187.   printf( "percentage X savings = %2.2f\n", percentage_x );
  188. #endif
  189.  
  190.   /* Relying on the loader to execute a def_bitmap instruction before */
  191.   /* loading the GP instruction list generated by this program.       */
  192.  
  193.   /* Convert each color in the bitmap into scan lines - one color at a time */
  194.   for( i = index = 0; i < MAX_NUM_COLORS; i++ )
  195.   {
  196.      if ( colors[i].count == 0L )     continue;     /* skip non-existant colors */
  197.      buff_overflow = FALSE;
  198.      n = extract_scan_lines((long)(index << 1),colors, i, buff, &buff_overflow);
  199.      if ( buff_overflow )
  200.      {
  201.           fprintf( stderr, "GP instruction list overflow.\n" );
  202.           exit( 1 );
  203.      }
  204.      /* If the newly extracted scan lines array can't fit into the GP */
  205.      /* instruction buffer, store instruction built up so far, and    */
  206.      /* start filling the buffer from the begining.                   */
  207.      if (( index + n ) > GP_BUFF_SIZE )
  208.      {
  209.           /* Flag the user if a color generates more lines than there is */
  210.         /* space in the instruction buffer. Very unlikely.             */
  211.           if ( index <= 0 )
  212.           {
  213.                fprintf( stderr, "Instruction list overflow.\n" );
  214.                exit( 1 );
  215.           }
  216.           /* store GP instruction built up so far */
  217.           write_buffer_to_file( f2, gp_buff, index );
  218.  
  219.           /* adjust the addresses in the GP instruction set */
  220.           /* since the GP code is not relocatable.          */
  221.           index = 0;
  222.           buff[ 4 ] = (int)(( 20L ) & 0xffffL );   /* scan line array address */
  223.           buff[ 5 ] = (int)(( 20L ) >> 16 );
  224.           buff[ 8 ] = (int)(( (long)( n << 1 )) & 0xffffL );  /* link address */
  225.           buff[ 9 ] = (int)(( (long)( n << 1 )) >> 16);
  226.      }
  227.      /* copy elements from temporary buffer into instruction buffer */
  228.      for ( j = 0; j < n; )
  229.           gp_buff[ index++ ] = buff[ j++ ];
  230. #if DEBUG
  231.      printf( "index = %d\n", index );
  232. #endif
  233.   }
  234.   /* store whatever is left in the very last buffer */
  235.   if ( index > 0 )
  236.      write_buffer_to_file( f2, gp_buff, index );
  237.  
  238. #if MOVSW_ON
  239.   /* XENIX specific - disable movesw in the 82786 driver */
  240.   if ( regdata.rdata.regval == FALSE )
  241.      ioctl( p6handle, CLEAR_SFLAG, &value );
  242. #endif
  243.  
  244.   return( 0 );          /* DONE!!! Wasn't that simple?! */
  245. }
  246. /*-------------------------------------------------------------------------*/
  247. /* Scan through the bitmap once and fill the 'colors' array with some      */
  248. /* very useful data about each color - how many times it apears in the     */
  249. /* bitmap and where in the bitmap it resides (define a window of existance */
  250. /* for each color. Return number of colors that were found in the bitmap.  */
  251. /*-------------------------------------------------------------------------*/
  252. find_all_colors( colors, num_lines )
  253. color_t colors[];   /* array of colors - 256 elements */
  254. int     num_lines;  /* number of lines in the bitmap  */
  255. {
  256.      register int     x;           /* x coordinate on a scan line          */
  257.      register color_t *color_ptr;  /* pointer - for speed                  */
  258.      register int     n;           /* number of bytes in a scan line       */
  259.      int  line,                    /* present scan line in the bitmap      */
  260.          num_colors;              /* number of colors found in the bitmap */
  261.  
  262. #if DEBUG_1
  263.      printf("Entered find_all_colors routine. num_lines = %d\n", num_lines );
  264. #endif
  265.      /* Initialize the 'colors' array. */
  266.      for( x = 0; x < MAX_NUM_COLORS; )
  267.      {
  268.           color_ptr = &colors[x++];        /* use a pointer for speed */
  269.           color_ptr->count = 0L;
  270.           color_ptr->begin_y = color_ptr->end_y = 0;
  271.           color_ptr->begin_x = color_ptr->end_x = 0;
  272.      }
  273.  
  274.      /* Scan and analyze the bitmap one line at a time. */
  275.      for ( line = 0; line < num_lines; line++ )
  276.      {
  277.           n = get_scan_line( bm_address, line_buff, line, bm_width );
  278.           for( x = 0; x < n; x++ )
  279.           {
  280.                color_ptr = &( colors[ line_buff[x] ]);
  281.  
  282.                /* mark the begining scan line for this color */
  283.                if ( color_ptr->count++ == 0L )
  284.                {
  285.                     color_ptr->begin_y = line;
  286.                     color_ptr->begin_x = x;
  287.                }
  288.                /* adjust the ending scan line each time a color is detected */
  289.                color_ptr->end_y = line;
  290.  
  291.                /* adjust x window for a color if needed */
  292.                if ( x < color_ptr->begin_x )     color_ptr->begin_x = x;
  293.                if ( x > color_ptr->end_x   )     color_ptr->end_x   = x;
  294.           }
  295.      }
  296.  
  297.      for ( x = num_colors = 0; x < MAX_NUM_COLORS; )
  298.           if ( colors[x++].count > 0L )     num_colors++;
  299.  
  300. #if DEBUG_1
  301.      printf( "Exited find_all_colors routine.\n" );
  302. #endif
  303.      return( num_colors );
  304. }
  305. /*-------------------------------------------------------------------------*/
  306. /*               The heart of compression.                                 */
  307. /* Procedure to extract scan lines from a bitmap file (with some help from */
  308. /* 'colors' array). Assumes that the GP buffer is impossible to overrun    */
  309. /* (left as an exercise to correct). The best way to understand this one   */
  310. /* is to go through it with a particular bitmap in mind.                   */
  311. /*-------------------------------------------------------------------------*/
  312. extract_scan_lines( start_addr, colors, color, buff, overflow )
  313. long  start_addr;   /* starting address of this GP instruction list */
  314. color_t  colors[];  /* colors description array                     */
  315. int       color,        /* color that is being extracted                */
  316.       buff[],       /* gp instruction buffer                        */
  317.       overflow;     /* overflow flag, gets set if the instruction buffer end */
  318.                     /* is reached = ( num_elements - GP_BUFF_THRESHOLD )     */
  319. {
  320.      /* Keep x and y coordinates from call to call - needed to calculate */
  321.      /* dx and dy of the next scan line array.                           */
  322.      static     int     x = 0,          /* present x coordinate */
  323.                     y = 0;          /* present y coordinate */
  324.      register     i, count, line;
  325.      int  index, dy;          /* gp instruction buffer index */
  326.      int  n, num_lines,
  327.           num_lines_index, first_time;
  328.      int  link_lower, link_upper;
  329.      BOOLEAN  within_scan_line;
  330.  
  331. #if DEBUG
  332.      printf( "color = %d\n",color );
  333. #endif
  334.  
  335.      /* Start at the begining of a buffer and add the GP instructions      */
  336.      /* to define color, scan lines, and link (around the array).          */
  337.      /* Relies on the loader to def_bitmap, texture, and raster operation. */
  338.      index = 0;
  339.  
  340.      /* def_color instruction */
  341.      buff[ index++ ] = 0x3d00;
  342.      buff[ index++ ] = (((int)color ) | (((int)color ) << 8));
  343.      buff[ index++ ] = 0;
  344.  
  345.      /* scan_lines instruction */
  346.      buff[ index++ ] = 0xba00;
  347.      buff[ index++ ] = (int)(( start_addr + 20L ) & 0xffffL );
  348.      buff[ index++ ] = (int)(( start_addr + 20L ) >> 16 );
  349.      num_lines_index = index++;    /* number of lines in the scan lines */
  350.                                   /* array is not yet known.           */
  351.  
  352.      /* link instruction - jump around the array */
  353.      buff[ index++ ] = 0x0200;
  354.      link_lower = index++;         /* fill in when the number of elements is */
  355.      link_upper = index++;         /* known.                                 */
  356.  
  357.      num_lines = 0;
  358.      first_time = TRUE;
  359.  
  360.      /* start at the bottom of the window (of this color)           */
  361.      /* and process one line at a time until the top of the window. */
  362.      dy = line = colors[ color ].begin_y;
  363.      for ( ; line <= colors[ color ].end_y; line++ )
  364.      {
  365.           n = get_scan_line( bm_address, line_buff, line, bm_width );
  366.           count = 0;
  367.           within_scan_line = FALSE;
  368.  
  369.           /* Process the line one pixel at a time */
  370.           n = colors[ color ].end_x;
  371.           for( i = colors[ color ].begin_x; i <= n; i++ )
  372.           {
  373.                if ( line_buff[i] != color )
  374.                {
  375.                     /* found a pixel that is not of desired color */
  376.                     if ( within_scan_line )
  377.                     {
  378.                          /* reached the end of scan line of desired color */
  379.                          buff[ index++ ] = --count;   /* length of it */
  380.                          within_scan_line = FALSE;
  381.                          y += dy;
  382.                          count = dy = 0;
  383.                          num_lines++;
  384.                     }
  385.                     continue;      /* to the next pixel */
  386.                }
  387.                else     /* found a pixel of desired color */
  388.                {
  389.                     if ( ! within_scan_line )     /* found the begining */
  390.                     {
  391.                          buff[ index++ ] = i - x; /* dx for scan line instruction */
  392.                          x = i;
  393.                          if ( first_time )
  394.                          {
  395.                               /* first time for this color */
  396. #if DEBUG_2
  397.      printf( "first time, y = %d, dy = %d\n", y, dy );
  398. #endif
  399.                               buff[ index++ ] = dy - y;     /* dy for scan line */
  400.                               y = dy;
  401.                               dy = 0;          /* reset dy, now that we've moved  */
  402.                               first_time = FALSE;
  403.                          }
  404.                          else
  405.                               buff[ index++ ] = dy;     /* dy for scan line instr. */
  406.                          within_scan_line = TRUE;     /* signal the begining edge */
  407.                     }
  408.                     count++;
  409.  
  410.                     /* Take care of the last pixel == color case */
  411.                     if ( i == n )
  412.                     {
  413.                          buff[ index++ ] = --count;
  414.                          within_scan_line = FALSE;
  415.                          y += dy;
  416.                          count = dy = 0;
  417.                          num_lines++;
  418.                     }
  419.                }
  420.           }
  421. #if DEBUG_1
  422.           printf( "x = %d,\t y = %d\n", x, y );
  423. #endif
  424.           dy++;
  425.      }
  426.      /* Now, the number of lines of this color is known.                      */
  427.      /* Therefore, scan line array instruction and link address can be filled.*/
  428.      buff[ num_lines_index ] = num_lines;
  429.      buff[ link_lower ] = (int)(( start_addr + (long)( index << 1)) & 0xffffL );
  430.      buff[ link_upper ] = (int)(( start_addr + (long)( index << 1)) >> 16);
  431. #if DEBUG_2
  432.      printf( "num_lines = %d,\tx = %d,\t y = %d\n", num_lines, x, y );
  433. #endif
  434.      return( index );
  435. }
  436. /*--------------------------------------------------------------*/
  437. /* Procedure that writes the GP instruction list to a file.     */
  438. /* An appropriate header is added before the GP list.           */
  439. /*--------------------------------------------------------------*/
  440. write_buffer_to_file( fd, buff, num_of_elements )
  441. int  fd,                /* output file descriptor            */
  442.      buff[],            /* pointer to the buffer             */
  443.      num_of_elements;   /* number of elements to be written  */
  444.                         /* each element is 16 bits (integer) */
  445. {
  446.      /* Header - placed before every block (8 bytes) */
  447.      struct     header
  448.      {
  449.           int          type;               /* 0 - GP instructions, 1 - bitmap     */
  450.           long     addr;               /* load address, ffffffff - don't care */
  451.           int          num_bytes;          /* number of bytes                     */
  452.      };
  453.      typedef     struct header     header_t;
  454.      header_t     hdr;
  455.  
  456.      /* Write the header into the file */
  457.      hdr.type = 0;
  458.      hdr.addr = 0L;          /* tell the loader to place instructions */
  459.                             /* address 0 in 82786 memory.            */
  460.      hdr.num_bytes = num_of_elements << 1;
  461.  
  462.      /* Write the header into the output file */
  463.      if ( write( fd, &hdr, sizeof( hdr )) != sizeof( hdr ))
  464.      {
  465.           fprintf( stderr, "compact: Write error.\n" );
  466.           exit(1);
  467.      }
  468.  
  469.      /* Write the GP instruction list into the output file */
  470.      if ( write( fd, buff, num_of_elements << 1 ) != ( num_of_elements << 1 ))
  471.      {
  472.           fprintf( stderr, "compact: Write error.\n" );
  473.           exit(1);
  474.      }
  475.      return( OK );
  476. }
  477. /*--------------------------------------------------------------------*/
  478. /* Procedure to read any scan line from the bitmap stored in graphics */
  479. /* memory. Swap bytes to make scanning easier.                        */
  480. /*--------------------------------------------------------------------*/
  481. get_scan_line( base_addr, buff_gsl, line, line_width )
  482. long  base_addr;            /* starting address of the bitmap */
  483. unsigned char  *buff_gsl;   /* scan line buffer               */
  484. int   line,                 /* which line to read             */
  485.       line_width;           /* how many pixels in a line      */
  486. {
  487.      long     address;
  488.  
  489. #if DEBUG_1
  490.      printf( "Entered get_scan_line routine. addr = %lx", addr );
  491.      printf( "\tline = %d\tline_width = %d\n", line, line_width );
  492. #endif
  493.  
  494.      address = base_addr + ((long)( line ) * (long)( line_width ));
  495.      getmem( p6handle, address, buff_gsl, line_width >> 1 );
  496.      swab( buff_gsl, buff_gsl, line_width );
  497.  
  498.      /* be carefull with swab (note that source and destination are the same) */
  499.      /* functionality depends on implementation of the swab routine.          */
  500.  
  501. #if DEBUG_1
  502.      printf("Exited get_scan_line routine.\n");
  503. #endif
  504.      return( line_width );
  505. }
  506.  
  507.  
  508.  
  509. [LISTING TWO]
  510.  
  511.  
  512. /*            A simple GP instruction list loader.                          */
  513. /*          Created by Victor J. Duvanenko                                  */
  514. /*                                                                          */
  515. /* Loads a GP instruction list from a file into 82786 memory and instructs  */
  516. /* the GP to execute them. If the file contains more instructions they are  */
  517. /* read in. The loader then waits for the GP to finish the previous list.   */
  518. /* Only when the GP is finished does the loader place the new list in 82786 */
  519. /* memory.                                                                  */
  520. /*                                                                          */
  521. /* Usage:           load file_name                                          */
  522. /*                                                                          */
  523. /* Input:  Binary file of the followind format                              */
  524. /*        a) Header                                                         */
  525. /*           1) type ( 0 - GP instructions, 1 - bitmap data ).              */
  526. /*           2) 32 bit address (lets the loader know where to place the     */
  527. /*              data in graphics/82786 memory). If equal to 0xffffffff      */
  528. /*              then the loader can place data anywhere.                    */
  529. /*           3) number of bytes to load.                                    */
  530. /*        b) Data                                                           */
  531. /*           1) GP instruction list.                                        */
  532. /*                                                                          */
  533. /* Output:  GP instructions are loaded into 82786 memory.                   */
  534. /*                                                                          */
  535. /* The loader provides the following services (may harm some applications)  */
  536. /* 1) def_bitmap, def_texture, and raster_op instructions with certain      */
  537. /*    defaults are executed before loading the GP instruction list.         */
  538. /* 2) "stop" instruction is placed at the end of every GP list - 'nop' with */
  539. /*     GCL bit set.                                                         */
  540. /* 3) Load time quote in milliseconds.                                      */
  541.  
  542. #include<stdio.h>
  543. #include<fcntl.h>
  544. #include<sys/types.h>
  545. #include<sys/timeb.h>
  546. #include "/usr/tls786/h/tls786.h"
  547. #include "/usr/tls786/h/tv1786.h"
  548.  
  549.  
  550. #define BUFF_SIZE     32600
  551. #define BOOLEAN          int
  552. #define TRUE          1
  553. #define FALSE          0
  554. #define OK               1
  555. #define     INTERVAL     1     /* Sampling period in milliseconds */
  556. #define WAIT          5000     /* wait period for the GP or DP to finish */
  557. #define     COMM_BUF_BOTTOM     0L
  558.  
  559. #define DEBUG          FALSE
  560. #define DEBG_1          FALSE
  561.  
  562. /* GP instruction list buffer */
  563. unsigned     char     buff[ BUFF_SIZE ];
  564.  
  565. main(argc,argv)
  566. int argc;
  567. char *argv[];
  568. {
  569.      register i;
  570.      int p6handle, f1, n_items, ellapsed_time, value;
  571.      struct timeb time_before, time_after;
  572.      long     addr,
  573.           addr_bm;    /* bitmap base address */
  574.  
  575.      /* Header - placed before every block (8 bytes) */
  576.      struct     header
  577.      {
  578.           int          type;        /* 0 - GP instructions, 1 - Bitmap     */
  579.           long     addr;        /* load address, ffffffff - don't care */
  580.           int          num_bytes;   /* number of bytes                     */
  581.      };
  582.      typedef     struct header     header_t;
  583.  
  584.      header_t     hdr;
  585.  
  586.      /* XENIX specific - turns on movsw instruction */
  587.      union
  588.      {
  589.           struct  tv1_cntrl brddata;
  590.           byte    rawdata[ sizeof( struct tv1_cntrl )];
  591.           struct  io_data   rdata;
  592.      }regdata;
  593.  
  594.   /* Check command line for proper usage - just a little. */
  595.   if (argc == 1)
  596.   {
  597.     fprintf( stderr, "Usage is: %s file_name\n", argv[0] );
  598.     exit(1);
  599.   }
  600.  
  601.   /* Open the input file for reading only. */
  602.   if (( f1 = open( argv[1], O_RDONLY ))  == -1 )
  603.   {
  604.      fprintf( stderr, "%s: Can't open %s.\n", argv[0], argv[1] );
  605.      exit(1);
  606.   }
  607.  
  608.   /* XENIX specific - enable the 82786 driver. */
  609.   p6handle = open786( MASTER_786 );
  610.   if ( p6handle == NULL )     {
  611.      fprintf( stderr, "%s: Can't access 82786.\n", argv[0] );
  612.      exit(1);
  613.   }
  614.  
  615.   /* XENIX specific - enable the use of movsw instruction driver. */
  616.   value = 0;
  617.   ioctl( p6handle, TEST_SFLAG, ®data );
  618.   if ( regdata.rdata.regval == FALSE )
  619.      ioctl( p6handle, SET_SFLAG, &value );
  620.  
  621.   addr = 0L;
  622.   addr_bm = 0x10000L;
  623.   ftime( &time_before );            /* Get present time stamp */
  624.  
  625.   /* A bit of overhead to make sure that the bitmap and texture are defined */
  626.   /* before the GP command list is loaded.                                  */
  627.      i = 0;
  628.      buff[ i++ ] = 0x00;          /* Def_bitmap */
  629.      buff[ i++ ] = 0x1a;
  630.      buff[ i++ ] = 0x00;
  631.      buff[ i++ ] = 0x00;
  632.      buff[ i++ ] = 0x01;
  633.      buff[ i++ ] = 0x00;
  634.      buff[ i++ ] = 0x7f;          /* 640 (for now) */
  635.      buff[ i++ ] = 0x02;
  636.      buff[ i++ ] = 0xdf;          /* by 480 (for now) */
  637.      buff[ i++ ] = 0x01;
  638.      buff[ i++ ] = 0x08;          /* 8bpp (for now) */
  639.      buff[ i++ ] = 0x00;
  640.  
  641.      buff[ i++ ] = 0x00;          /* Def_logical_op */
  642.      buff[ i++ ] = 0x41;
  643.      buff[ i++ ] = 0xff;
  644.      buff[ i++ ] = 0xff;
  645.      buff[ i++ ] = 0x05;
  646.      buff[ i++ ] = 0x00;
  647.  
  648.      buff[ i++ ] = 0x00;          /* Def_texture */
  649.      buff[ i++ ] = 0x06;
  650.      buff[ i++ ] = 0xff;
  651.      buff[ i++ ] = 0xff;
  652.  
  653.      buff[ i++ ] = 0x01;          /* stop */
  654.      buff[ i++ ] = 0x03;
  655.  
  656.      /* Wait for a previous GP command list to finish */
  657.      if ( waitgp( p6handle, INTERVAL, WAIT ) < 0 )     {
  658.           printf("GP is hung!!!\n");
  659.           exit(1);
  660.      }
  661.        /* Place it in 786 graphics memory */
  662.        putmem( p6handle, addr, buff, i >> 1 );
  663.  
  664.      /* Direct the GP to execute the command */
  665.      putreg( p6handle, GRP_GR1, (int)( addr & 0xffff ));
  666.      putreg( p6handle, GRP_GR2, (int)( addr >> 16 ));
  667.      putreg( p6handle, GRP_GR0, 0x200 );
  668.  
  669.   /* Now, for the GP list from an input file. */
  670.   /* Read the header and then the data.       */
  671.   while (( n_items = read( f1, &hdr, sizeof( hdr ))) > 0 )
  672.   {
  673.      i = 0;
  674.      if ( n_items != sizeof( hdr ))
  675.      {
  676.           printf( stderr, "%s: Read error.\n", argv[0] );
  677.           exit(1);
  678.      }
  679.     /* does it matter where the GP list is placed? */
  680.      if ( hdr.addr != 0xffffffffL )     addr = hdr.addr;
  681.  
  682.      /* GP instruction list */
  683.      if ( hdr.type == 0 )
  684.      {
  685.           if (( n_items = read( f1, buff, hdr.num_bytes )) == hdr.num_bytes )
  686.           {
  687.                /* Add a "stop" command to the GP instruction list */
  688.                i += n_items;
  689.                buff[ i++ ] = 0x01;
  690.                buff[ i++ ] = 0x03;
  691.  
  692.                /* Wait for the GP to finish any previous instruction */
  693.                if ( waitgp( p6handle, INTERVAL, WAIT ) < 0 )
  694.                {
  695.                     fprintf( stderr, "GP is hung!!!\n" );
  696.                     exit( 1 );
  697.                }
  698.  
  699.                  /* Place it in 786 graphics memory */
  700.                  putmem( p6handle, addr, buff, i >> 1 );
  701.           }
  702.           else
  703.           {
  704.                printf( stderr, "%s: Read error.\n", argv[0] );
  705.                exit(1);
  706.           }
  707.           /* Direct the GP to execute the command */
  708.           putreg( p6handle, GRP_GR1, (int)( addr & 0xffff ));
  709.           putreg( p6handle, GRP_GR2, (int)( addr >> 16 ));
  710.           putreg( p6handle, GRP_GR0, 0x200 );
  711.      }
  712.      /* Is it bitmaps - then place the data at that address */
  713.      if ( hdr.type == 1 )
  714.      {
  715.           if (( n_items = read( f1, &buff[i], hdr.num_bytes )) == hdr.num_bytes )
  716.           {
  717.                  /* Place it in 786 graphics memory */
  718.                  putmem( p6handle, addr_bm + hdr.addr, buff, n_items >> 1 );
  719.           }
  720.      }
  721.   }
  722.  
  723.   /* Get the time stamp after the loading is done. */
  724.   ftime( &time_after );
  725.   ellapsed_time = (int)( time_after.time - time_before.time ) * 1000;
  726.   ellapsed_time += ( time_after.millitm - time_before.millitm );
  727.   printf( "%dms\n", ellapsed_time );
  728.  
  729.   /* XENIX specific - disable movesw in the 786 driver */
  730.   if ( regdata.rdata.regval == FALSE )
  731.      ioctl( p6handle, CLEAR_SFLAG, &value );
  732.  
  733.   return(0);
  734. }
  735.  
  736.  
  737.  
  738.