home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / m / makepcx / source / c / makepcx < prev    next >
Encoding:
Text File  |  1991-12-08  |  13.8 KB  |  588 lines

  1. /*******************************************************************************
  2.  
  3.     makepcx.c
  4.  
  5.     $Header$
  6.     
  7.     (c) Daniel Pead 1991
  8.  
  9.     Converts RISC-OS Sprites into Zsoft PCX V5 files.
  10.  
  11.     This file contains the principal make_pcx function, and should be
  12.     linked with either the CLI or WIMP front end.
  13.  
  14.     This software may be freely distributed.
  15.  
  16. $Log$
  17.  
  18. *******************************************************************************/
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <stddef.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25.  
  26. #include <errno.h>
  27. #include <sprite.h> 
  28. #include <kernel.h>
  29. #include <swis.h>
  30.  
  31. #include "makepcx.h"
  32. #include "palettes.h"
  33.  
  34.  
  35. /* Palette to use for sprites without own palette */
  36.  
  37. int default_pal_type = 1;     /* 0 = BBC, 1 = Desktop, 2 = file         */
  38. int force_pal = 0;            /* Apply default palette to all sprites */
  39.  
  40. /* VDU variable number - Log2 of Bytes per "character" - more applicable to */
  41. /* sprites than bits-per-pixel                                                */ 
  42.  
  43. #define VDU_Log2BPC    10
  44.  
  45. /* Size of buffer for packed line - Worst case for 640x?x256 image            */
  46.  
  47. #define LBUF_SIZE 1280
  48.  
  49.  
  50. /*******************************************************************************
  51.  
  52.     make_pcx
  53.  
  54.     Convert sprite to PCX/PCC format and write to file pcxout
  55.  
  56.     256 colour sprites         -> 8-bits per pixel x 1 plane PCX
  57.     16 and 4 colour sprites -> 1-bit per pixel x 4 planes PCX
  58.     2 colour spites            -> 1-bit pre pixel x 1 plane PCX
  59.  
  60.     For 256 colour sprites, a representation of the Archimedes' 256 colours
  61.     (essentially fixed) is appended.
  62.  
  63.     For 16, 4 and 2 colour sprites without palette, either the BBC palette
  64.     or the Desktop palette is included (selected via global var
  65.     default_pal_type)
  66.  
  67.     Otherwise, the sprite's own palette is included.
  68.  
  69. *******************************************************************************/
  70.                          
  71. int make_pcx ( sprite_area * sp_area_p, sprite_ptr sp_p, FILE * pcxout )
  72. {
  73.     pcx_hdr_t pcx_hdr;
  74.     sprite_id sp_id;
  75.     int words;
  76.  
  77.     ubyte line_buffer[LBUF_SIZE];
  78.     int bpp, h, w;
  79.  
  80.     int line;
  81.     int line_len;
  82.     int * line_p;
  83.  
  84.     for ( h=0; h<58; pcx_hdr.pad[h++]=0 );    
  85.  
  86.     /* First fill out common pcx header constants  */
  87.     
  88.     pcx_hdr.code = 10;         pcx_hdr.version = 5;
  89.     pcx_hdr.encoding = 1;    pcx_hdr.reserved = 0;
  90.     pcx_hdr.palinfo = 1;
  91.     
  92.     /* Get other required info on sprite & palette */
  93.     
  94.     pre_process_sprite ( sp_area_p, sp_p, &sp_id, &bpp, &words, &w, &h,
  95.         pcx_hdr.palette );
  96.  
  97.     /* & Continue filling in header */
  98.  
  99.     pcx_hdr.minx = (uword) 0;        pcx_hdr.miny = (uword) 0;
  100.     pcx_hdr.maxx = (uword) w-1;        pcx_hdr.maxy = (uword) h-1;
  101.  
  102.     pcx_hdr.bits = (bpp==8) ? 8 : 1; /* and you thought the arc was odd... */
  103.     pcx_hdr.planes = (bpp==8 || bpp == 1) ? 1 : 4;
  104.  
  105.     pcx_hdr.hres = w;
  106.     pcx_hdr.vres = h;
  107.  
  108.     pcx_hdr.line_length = (pcx_hdr.bits*w + 7) / 8;
  109.  
  110.     /* Now write the header to disc */
  111.  
  112.     if ( !fwrite ( (void *) &pcx_hdr, 128, 1, pcxout ) )
  113.         do_c_error ( errno );
  114.     
  115.     /* And now, encode & save each line of the sprite  */
  116.  
  117.     line_p = (int *) ( ((ubyte *) sp_p) + sp_h(sp_p).image );
  118.  
  119. #ifdef DEBUG
  120.     printf ( " Width : %d pixels, %x words. Bpp = %d\n",w,words,bpp );
  121. #endif
  122.     
  123.     for ( line = 1; line<=h; line++ )
  124.     {
  125. #ifdef DEBUG
  126.         printf ( "Encoding line at %p",line_p);
  127. #endif
  128.         line_len = encode_pcx ( line_buffer, line_p, w, bpp );
  129. #ifdef DEBUG
  130.         printf ( " -> encoded length %d\n",line_len );
  131. #endif    
  132.         if ( ! fwrite( (void *) line_buffer, line_len, 1, pcxout ) )
  133.             do_c_error ( errno );
  134.         line_p += words;
  135.     }
  136.  
  137.     /* If 8-bit mode, dump 256 colour palette */
  138.     
  139.     if (bpp == 8)
  140.     {
  141.         fputc ( 0x0c, pcxout );
  142.         if ( fwrite( (void *) pal_acorn256, 3, 256, pcxout ) != 256 )
  143.             do_c_error ( errno );
  144.     }
  145.  
  146.     return TRUE;
  147. }
  148.  
  149.  
  150. /*******************************************************************************
  151.  
  152.     Translate one row of sprite, starting from line_p, into PCX Run-length
  153.     encoded data in out_buffer.
  154.  
  155.     Width = width (in pixels) of sprite.
  156.     bpp = bits-per-pixel of sprite.
  157.  
  158.     Returns length in bytes of encoded row.
  159.  
  160.     PCX RLE format - string of bytes in which:
  161.  
  162.         <11nnnnnn> <dddddddd> =     Byte dddddddd repeated nnnnnn times
  163.  
  164.         <dddddddd> =                 Single byte dddddddd, unencoded.
  165.  
  166.     Any data bytes with top 2 bits set have to be encoded as 2 bytes:
  167.  
  168.         <11000001> <dddddddd>
  169.  
  170.     Could be made faster by "unrolling" 1, 2 and 4 pixel cases from main loop,
  171.     but it runs in nothing flat, anyhow.        
  172.     
  173. *******************************************************************************/
  174.  
  175. int encode_pcx ( ubyte * out_buffer, int * line_p, int width, int bpp )
  176. {
  177.     int oldval, count, value;        /* For run-length encoding                 */
  178.     int plane, bit;                    /* EGA plane & bit counters                */
  179.     int data_word;                    /* Holds current word of sprite data     */
  180.     int pixels_left;                /* Horizontal pixels remaining            */
  181.     int planes;                        /* Number of EGA bit-planes in output    */ 
  182.     
  183.     ubyte * buffer = out_buffer;    /* Next free byte in output buffer        */
  184.     ubyte * byte_p;                    /* Pointer to next byte in sprite data    */
  185.  
  186.     count = 0; oldval = 0;            /* Initialise RLE */
  187.  
  188.  
  189.     /* Decide number of EGA colour planes - 1 for 2 or 256 colours             */
  190.     /* 4 for 16 colour                                                         */
  191.     
  192.     planes = ( bpp == 8 || bpp == 1) ? 1 : 4;
  193.  
  194.     /* Encode whole row for each colour plane in turn. RLE "runs" may        */ 
  195.     /* carry over between planes.                                            */   
  196.  
  197.             
  198.     for (plane = 1; plane<=planes; plane++ )
  199.     {
  200.  
  201.         /* 1, 2 and 4 BPP modes     */
  202.         /* Encode one plane of row     */
  203.         
  204.         byte_p = (ubyte *) line_p;            /* Next byte of sprite data */
  205.         pixels_left = width;    
  206.         
  207.         while (pixels_left > 0)
  208.         {
  209.             if ( bpp==8 )
  210.             {
  211.                 /* Simple case - 1 byte = 1 pixel - just read off the byte     */
  212.                 value = *byte_p++;
  213.                 pixels_left-=1;
  214.             }            
  215.             else
  216.             {
  217.  
  218.                 /* build 1 byte of EGA data by extrcting bit number <plane> */
  219.                 /* from each of 8 adjacent pixels.                               */
  220.  
  221.                 /* May as well go through all this for 1-bit modes because,    */
  222.                 /* well, there's two ways round you can put pixels into a    */
  223.                 /* byte - and guess what....                                */
  224.                 
  225.                 /* It's bit twiddling time! */
  226.                 
  227.                 value = 0;
  228.                 
  229.                 /* Get the word and shift so that the first */
  230.                 /* bit for this plane is in bit 0           */
  231.         
  232.  
  233.                 if ( plane <= bpp ) /* In 2-bpp mode, planes 3&4 are all 0 */
  234.                 {                            
  235.                     data_word = (* ((int *) byte_p) ) >> (plane-1);
  236.  
  237.                     /* Now peel off every bpp'th bit into result */
  238.  
  239.                     for (bit=7; bit>=0; bit--)
  240.                     {
  241.                         value |= (data_word & 1)<<bit;
  242.                         data_word = data_word >> bpp;
  243.                     }
  244.                 }
  245.                 /* Now move on */            
  246.                 byte_p+=bpp;    /* We've now encoded bpp*8 bits of data */
  247.                 pixels_left-=8;
  248.  
  249.                 /* Unless width is multiple of 8, will overrun by a few pixels     */
  250.                 /* Shouldn't matter because each row of sprite data is             */
  251.                 /* already padded out to word boundary                            */
  252.             }
  253.  
  254.             /* O.k. - now run-lenth encode the value */
  255.  
  256.             if (!count) oldval=value;
  257.             
  258.              if (  value == oldval && count<0x3F )
  259.                  /* Still running */
  260.                 count++;
  261.              else
  262.              {
  263.                  /* Flush out run */
  264.                  
  265.                  if ( count == 1 && (oldval & 0xC0)!=0xC0 )
  266.                      *buffer++ = oldval;
  267.                  else
  268.                  {
  269.                      *buffer++ = count | 0xC0;
  270.                      *buffer++ = oldval;
  271.                  }
  272.                  count = 1; oldval = value;
  273.             }
  274.         }
  275.     }
  276.  
  277.     /* Flush out last RLE data */
  278.  
  279.     if ( count == 1 && (oldval & 0xC0)!=0xC0 )
  280.         *buffer++ = oldval;
  281.     else
  282.     {
  283.         *buffer++ = count | 0xC0;
  284.         *buffer++ = oldval;
  285.     }
  286.  
  287.     return (int) (buffer - out_buffer);
  288. }
  289.     
  290.  
  291. /*******************************************************************************
  292.  
  293.     In the absence of palette info, choose a default palette for a given
  294.     number of bits per pixel
  295.  
  296. *******************************************************************************/
  297.  
  298. ubyte * choose_palette ( int bpp )
  299. {
  300.     if ( default_pal_type == 1 )
  301.         switch ( bpp )
  302.         {
  303.             case 1: return pal_desk_2;
  304.             case 2: return pal_desk_4;
  305.             case 4: return pal_desk_16;
  306.             case 8:    return pal_acorn256;
  307.             default: return NULL;
  308.         }
  309.     else
  310.         switch ( bpp )
  311.         {
  312.             case 1: return pal_bbc_2;
  313.             case 2: return pal_bbc_4;
  314.             case 4: return pal_bbc_16;
  315.             case 8:    return pal_acorn256;
  316.             default: return NULL;
  317.         }
  318. }
  319.  
  320.  
  321. /*******************************************************************************
  322.  
  323.     get_bpp_and_pal
  324.  
  325.     Work out the bits-per-pixel and palette info for a sprite.
  326.  
  327.     Returns BPP, or BPP & 0x100 if sprite has a palette.
  328.     
  329. *******************************************************************************/
  330.  
  331. int get_bpp_and_pal ( sprite_area * sp_area_p, sprite_ptr sp_p )
  332. {
  333.     sprite_id sp_id;
  334.     _kernel_swi_regs regs;
  335.     os_error * oserr_p;
  336.     sprite_info sp_info;
  337.     int bpp;
  338.     
  339.     /* Set up sprite id */
  340.     
  341.     sp_id.s.addr = sp_p;
  342.     sp_id.tag = sprite_id_addr;
  343.  
  344.     oserr_p = sprite_readsize ( sp_area_p, &sp_id, &sp_info );
  345.  
  346.     /* Read the bits-per-pixel for the appropriate mode */
  347.  
  348.     regs.r[0] = sp_info.mode;
  349.     regs.r[1] = VDU_Log2BPC;
  350.  
  351.     oserr_p = (os_error *) _kernel_swi ( OS_ReadModeVariable, ®s, ®s );
  352.  
  353.     if ( oserr_p ) do_os_error ( oserr_p );
  354.  
  355.     bpp = 1<<regs.r[2];
  356.     
  357.     if ( sp_h(sp_p).image  != 44 ) bpp |= 0x100;
  358.  
  359.     return bpp;
  360. }
  361.  
  362. /*******************************************************************************
  363.  
  364.     pre_process_sprite
  365.  
  366.     Given a pointer to the sprite area and sprite:
  367.  
  368.     1:     Set up the sprite id in *sprite_id_p;
  369.     2:     Remove LH wastage from the sprite;
  370.     3:     Get the height & width in pixels, the line length in words and the
  371.         bits per pixel.
  372.     4:    Unless a 256 colour sprite, extract palette in PCX form,
  373.         using appropriate default if none stored with sprite.
  374.  
  375. *******************************************************************************/
  376.  
  377.  
  378.  
  379. void pre_process_sprite ( sprite_area * sp_area_p, sprite_ptr sp_p,
  380.     sprite_id * sp_id_p,
  381.     int * bpp, int * words,
  382.     int * w, int * h, ubyte palette[] )
  383. {
  384.     os_error * oserr_p;
  385.     sprite_info sp_info;
  386.     int i, colours, haspal;
  387.     ubyte * src_pal_p;
  388.     
  389.     /* Set up sprite id */
  390.     
  391.     sp_id_p->s.addr = sp_p;
  392.     sp_id_p->tag = sprite_id_addr;
  393.  
  394.     /* Left-align sprite */
  395.  
  396.     if ( oserr_p = sprite_removewastage ( sp_area_p, sp_id_p ) )
  397.         do_os_error ( oserr_p );
  398.  
  399.     oserr_p = sprite_readsize ( sp_area_p, sp_id_p, &sp_info );
  400.  
  401.     if ( oserr_p ) do_os_error ( oserr_p );
  402.     
  403.     *bpp = get_bpp_and_pal ( sp_area_p, sp_p );
  404.  
  405.     haspal = (*bpp) & 0x100;
  406.     *bpp &=0xff;
  407.     
  408.     colours = 1<<*bpp;
  409.     
  410.     /* Get the height & width of the sprite */
  411.  
  412.     *h = sp_info.height; *w = sp_info.width;
  413.     *words = sp_h(sp_p).width + 1;
  414.  
  415.     /* Get the palette info */
  416.  
  417.     if (*bpp < 8)
  418.     {
  419.         if ( (!haspal) || force_pal )
  420.         {
  421.             /* default palette */            
  422.             src_pal_p = choose_palette(*bpp);
  423.             
  424.             for ( i=0; i< colours * 3; i++ )    palette[i] = *src_pal_p++;
  425.         }
  426.         else
  427.         {
  428.             src_pal_p = ((ubyte *) sp_p) + 40;
  429.             for ( i=0; i < colours*3; i++ )
  430.             {
  431.                 if ( i % 3 == 0 ) src_pal_p += 5; /* Skip over unwanted data */
  432.                 palette[i] = *src_pal_p++;
  433.             } 
  434.         }
  435.     }
  436. }
  437.  
  438. /*******************************************************************************
  439.  
  440.     finfo - Get file information
  441.  
  442.     If called with len non-zero gets length of file into *len
  443.     
  444.     returns:
  445.     
  446.         -1        : Not found
  447.         0-0xFFF    : File type for file found
  448.         0x1001    : Unstamped file found
  449.         0x1002  : Directory found
  450.  
  451. *******************************************************************************/
  452.  
  453. #define FINFO_ERR    -1
  454. #define FINFO_DIR    0x1002
  455. #define FINFO_DATA  0x1001
  456.     
  457. int finfo ( char * name, int * len )
  458. {
  459.     _kernel_osfile_block fileinfo;
  460.     int obtype;
  461.  
  462.     obtype = _kernel_osfile ( 17, name, & fileinfo );
  463.  
  464.     if ( len ) *len = fileinfo.start;
  465.  
  466.     if ( obtype==1 && (fileinfo.load & 0xFFF00000) == 0xFFF00000 )
  467.         return (fileinfo.load & 0xFFF00) >> 8;
  468.     else
  469.         return obtype ? (obtype | 0x1000)  : -1 ;
  470. }
  471.  
  472. /*******************************************************************************
  473.  
  474.     Set type of named file to 12-bit type
  475.  
  476.     Return <>0 if error.
  477.     
  478. *******************************************************************************/
  479.  
  480. int settype ( char * file, int type )
  481. {
  482.     _kernel_swi_regs regs;
  483.     os_error * oserr_p;
  484.     
  485.     regs.r[0] = 18;
  486.     regs.r[1] = (int) file;
  487.     regs.r[2] = type;
  488.     oserr_p = (os_error *) _kernel_swi ( OS_File, ®s, ®s );
  489.     return oserr_p ? oserr_p->errnum : 0;
  490. }    
  491.  
  492. /*******************************************************************************
  493.  
  494.     Make directory. Return error number if failed
  495.  
  496. *******************************************************************************/
  497.  
  498. int mkdir ( char * dir )
  499. {
  500.     _kernel_swi_regs regs;
  501.     os_error * oserr_p;
  502.     
  503.     regs.r[0] = 8;
  504.     regs.r[1] = (int) dir;
  505.     regs.r[4] = 0;
  506.     oserr_p = (os_error *) _kernel_swi ( OS_File, ®s, ®s );
  507.     return oserr_p ? oserr_p->errnum : 0;
  508. }
  509.  
  510.         
  511. /*******************************************************************************
  512.  
  513.     int strisnum ( char * s )
  514.  
  515.     Returns true if string s is a valid number. Preceeding 0x signifies
  516.     hex. You don't want to use octal, do you?
  517.  
  518. *******************************************************************************/
  519.  
  520. int strisnum ( char * s )
  521. {
  522.     int len;
  523.  
  524.     len = strlen(s);
  525.     
  526.     if ( *s == '0' && tolower(s[1]) == 'x' )
  527.         return ( strspn ( &s[2], "0123456789abcdefABCDEF" ) == len );
  528.     else
  529.         return ( strspn ( s, "0123456789" ) == len );
  530. }
  531.  
  532. /*******************************************************************************
  533.  
  534.     sprite_ptr sprite_find ( sprite_area * sp_area_p, int number, char * name )
  535.     
  536.     Return pointer to required sprite in sprite area. If n>0, then find
  537.     Nth sprite, otherwise find named sprite.
  538.  
  539.     If new_n_p is not null, number of sprite found is wriiten back.
  540.     
  541.     Returns null if not found
  542.  
  543. *******************************************************************************/
  544.  
  545. sprite_ptr sprite_find ( sprite_area * sp_area_p,
  546.         int number, char * name, int * new_n_p )
  547. {
  548.     char * cp1, * cp2;
  549.     int found; int count;
  550.     
  551.     sprite_header * sp_h_p, * next_h_p;
  552.  
  553.     /* Silly case... */
  554.     
  555.     if ( number > sp_area_p->number ) return NULL;
  556.  
  557.     next_h_p = (sprite_header * ) ( ((int) sp_area_p) + sp_area_p->sproff );
  558.     
  559.     count = 0;
  560.     cp1 = 0; cp2 = 0;
  561.  
  562.     do
  563.     {
  564.         sp_h_p = next_h_p;
  565.  
  566.         count++;
  567.         
  568.         if ( number )
  569.             found = (count==number);
  570.         else
  571.         {
  572.             for (
  573.                 cp1 = name, cp2 = sp_h_p->name;
  574.                 *cp1 && *cp2 && toupper(*cp1)==toupper(*cp2);
  575.                 cp1++, cp2++
  576.             );
  577.             found = (!*cp1) && (!*cp2);
  578.         }
  579.         next_h_p = (sprite_header *) ( ((int) sp_h_p) + sp_h_p->next );
  580.  
  581.     } while ( (!found) && count != sp_area_p->number );
  582.  
  583.     if ( found && new_n_p ) *new_n_p = count;
  584.     
  585.     return found ? (sprite_ptr) sp_h_p : NULL ;
  586. }
  587.  
  588.