home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************
-
- makepcx.c
-
- $Header$
-
- (c) Daniel Pead 1991
-
- Converts RISC-OS Sprites into Zsoft PCX V5 files.
-
- This file contains the principal make_pcx function, and should be
- linked with either the CLI or WIMP front end.
-
- This software may be freely distributed.
-
- $Log$
-
- *******************************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <string.h>
- #include <ctype.h>
-
- #include <errno.h>
- #include <sprite.h>
- #include <kernel.h>
- #include <swis.h>
-
- #include "makepcx.h"
- #include "palettes.h"
-
-
- /* Palette to use for sprites without own palette */
-
- int default_pal_type = 1; /* 0 = BBC, 1 = Desktop, 2 = file */
- int force_pal = 0; /* Apply default palette to all sprites */
-
- /* VDU variable number - Log2 of Bytes per "character" - more applicable to */
- /* sprites than bits-per-pixel */
-
- #define VDU_Log2BPC 10
-
- /* Size of buffer for packed line - Worst case for 640x?x256 image */
-
- #define LBUF_SIZE 1280
-
-
- /*******************************************************************************
-
- make_pcx
-
- Convert sprite to PCX/PCC format and write to file pcxout
-
- 256 colour sprites -> 8-bits per pixel x 1 plane PCX
- 16 and 4 colour sprites -> 1-bit per pixel x 4 planes PCX
- 2 colour spites -> 1-bit pre pixel x 1 plane PCX
-
- For 256 colour sprites, a representation of the Archimedes' 256 colours
- (essentially fixed) is appended.
-
- For 16, 4 and 2 colour sprites without palette, either the BBC palette
- or the Desktop palette is included (selected via global var
- default_pal_type)
-
- Otherwise, the sprite's own palette is included.
-
- *******************************************************************************/
-
- int make_pcx ( sprite_area * sp_area_p, sprite_ptr sp_p, FILE * pcxout )
- {
- pcx_hdr_t pcx_hdr;
- sprite_id sp_id;
- int words;
-
- ubyte line_buffer[LBUF_SIZE];
- int bpp, h, w;
-
- int line;
- int line_len;
- int * line_p;
-
- for ( h=0; h<58; pcx_hdr.pad[h++]=0 );
-
- /* First fill out common pcx header constants */
-
- pcx_hdr.code = 10; pcx_hdr.version = 5;
- pcx_hdr.encoding = 1; pcx_hdr.reserved = 0;
- pcx_hdr.palinfo = 1;
-
- /* Get other required info on sprite & palette */
-
- pre_process_sprite ( sp_area_p, sp_p, &sp_id, &bpp, &words, &w, &h,
- pcx_hdr.palette );
-
- /* & Continue filling in header */
-
- pcx_hdr.minx = (uword) 0; pcx_hdr.miny = (uword) 0;
- pcx_hdr.maxx = (uword) w-1; pcx_hdr.maxy = (uword) h-1;
-
- pcx_hdr.bits = (bpp==8) ? 8 : 1; /* and you thought the arc was odd... */
- pcx_hdr.planes = (bpp==8 || bpp == 1) ? 1 : 4;
-
- pcx_hdr.hres = w;
- pcx_hdr.vres = h;
-
- pcx_hdr.line_length = (pcx_hdr.bits*w + 7) / 8;
-
- /* Now write the header to disc */
-
- if ( !fwrite ( (void *) &pcx_hdr, 128, 1, pcxout ) )
- do_c_error ( errno );
-
- /* And now, encode & save each line of the sprite */
-
- line_p = (int *) ( ((ubyte *) sp_p) + sp_h(sp_p).image );
-
- #ifdef DEBUG
- printf ( " Width : %d pixels, %x words. Bpp = %d\n",w,words,bpp );
- #endif
-
- for ( line = 1; line<=h; line++ )
- {
- #ifdef DEBUG
- printf ( "Encoding line at %p",line_p);
- #endif
- line_len = encode_pcx ( line_buffer, line_p, w, bpp );
- #ifdef DEBUG
- printf ( " -> encoded length %d\n",line_len );
- #endif
- if ( ! fwrite( (void *) line_buffer, line_len, 1, pcxout ) )
- do_c_error ( errno );
- line_p += words;
- }
-
- /* If 8-bit mode, dump 256 colour palette */
-
- if (bpp == 8)
- {
- fputc ( 0x0c, pcxout );
- if ( fwrite( (void *) pal_acorn256, 3, 256, pcxout ) != 256 )
- do_c_error ( errno );
- }
-
- return TRUE;
- }
-
-
- /*******************************************************************************
-
- Translate one row of sprite, starting from line_p, into PCX Run-length
- encoded data in out_buffer.
-
- Width = width (in pixels) of sprite.
- bpp = bits-per-pixel of sprite.
-
- Returns length in bytes of encoded row.
-
- PCX RLE format - string of bytes in which:
-
- <11nnnnnn> <dddddddd> = Byte dddddddd repeated nnnnnn times
-
- <dddddddd> = Single byte dddddddd, unencoded.
-
- Any data bytes with top 2 bits set have to be encoded as 2 bytes:
-
- <11000001> <dddddddd>
-
- Could be made faster by "unrolling" 1, 2 and 4 pixel cases from main loop,
- but it runs in nothing flat, anyhow.
-
- *******************************************************************************/
-
- int encode_pcx ( ubyte * out_buffer, int * line_p, int width, int bpp )
- {
- int oldval, count, value; /* For run-length encoding */
- int plane, bit; /* EGA plane & bit counters */
- int data_word; /* Holds current word of sprite data */
- int pixels_left; /* Horizontal pixels remaining */
- int planes; /* Number of EGA bit-planes in output */
-
- ubyte * buffer = out_buffer; /* Next free byte in output buffer */
- ubyte * byte_p; /* Pointer to next byte in sprite data */
-
- count = 0; oldval = 0; /* Initialise RLE */
-
-
- /* Decide number of EGA colour planes - 1 for 2 or 256 colours */
- /* 4 for 16 colour */
-
- planes = ( bpp == 8 || bpp == 1) ? 1 : 4;
-
- /* Encode whole row for each colour plane in turn. RLE "runs" may */
- /* carry over between planes. */
-
-
- for (plane = 1; plane<=planes; plane++ )
- {
-
- /* 1, 2 and 4 BPP modes */
- /* Encode one plane of row */
-
- byte_p = (ubyte *) line_p; /* Next byte of sprite data */
- pixels_left = width;
-
- while (pixels_left > 0)
- {
- if ( bpp==8 )
- {
- /* Simple case - 1 byte = 1 pixel - just read off the byte */
- value = *byte_p++;
- pixels_left-=1;
- }
- else
- {
-
- /* build 1 byte of EGA data by extrcting bit number <plane> */
- /* from each of 8 adjacent pixels. */
-
- /* May as well go through all this for 1-bit modes because, */
- /* well, there's two ways round you can put pixels into a */
- /* byte - and guess what.... */
-
- /* It's bit twiddling time! */
-
- value = 0;
-
- /* Get the word and shift so that the first */
- /* bit for this plane is in bit 0 */
-
-
- if ( plane <= bpp ) /* In 2-bpp mode, planes 3&4 are all 0 */
- {
- data_word = (* ((int *) byte_p) ) >> (plane-1);
-
- /* Now peel off every bpp'th bit into result */
-
- for (bit=7; bit>=0; bit--)
- {
- value |= (data_word & 1)<<bit;
- data_word = data_word >> bpp;
- }
- }
- /* Now move on */
- byte_p+=bpp; /* We've now encoded bpp*8 bits of data */
- pixels_left-=8;
-
- /* Unless width is multiple of 8, will overrun by a few pixels */
- /* Shouldn't matter because each row of sprite data is */
- /* already padded out to word boundary */
- }
-
- /* O.k. - now run-lenth encode the value */
-
- if (!count) oldval=value;
-
- if ( value == oldval && count<0x3F )
- /* Still running */
- count++;
- else
- {
- /* Flush out run */
-
- if ( count == 1 && (oldval & 0xC0)!=0xC0 )
- *buffer++ = oldval;
- else
- {
- *buffer++ = count | 0xC0;
- *buffer++ = oldval;
- }
- count = 1; oldval = value;
- }
- }
- }
-
- /* Flush out last RLE data */
-
- if ( count == 1 && (oldval & 0xC0)!=0xC0 )
- *buffer++ = oldval;
- else
- {
- *buffer++ = count | 0xC0;
- *buffer++ = oldval;
- }
-
- return (int) (buffer - out_buffer);
- }
-
-
- /*******************************************************************************
-
- In the absence of palette info, choose a default palette for a given
- number of bits per pixel
-
- *******************************************************************************/
-
- ubyte * choose_palette ( int bpp )
- {
- if ( default_pal_type == 1 )
- switch ( bpp )
- {
- case 1: return pal_desk_2;
- case 2: return pal_desk_4;
- case 4: return pal_desk_16;
- case 8: return pal_acorn256;
- default: return NULL;
- }
- else
- switch ( bpp )
- {
- case 1: return pal_bbc_2;
- case 2: return pal_bbc_4;
- case 4: return pal_bbc_16;
- case 8: return pal_acorn256;
- default: return NULL;
- }
- }
-
-
- /*******************************************************************************
-
- get_bpp_and_pal
-
- Work out the bits-per-pixel and palette info for a sprite.
-
- Returns BPP, or BPP & 0x100 if sprite has a palette.
-
- *******************************************************************************/
-
- int get_bpp_and_pal ( sprite_area * sp_area_p, sprite_ptr sp_p )
- {
- sprite_id sp_id;
- _kernel_swi_regs regs;
- os_error * oserr_p;
- sprite_info sp_info;
- int bpp;
-
- /* Set up sprite id */
-
- sp_id.s.addr = sp_p;
- sp_id.tag = sprite_id_addr;
-
- oserr_p = sprite_readsize ( sp_area_p, &sp_id, &sp_info );
-
- /* Read the bits-per-pixel for the appropriate mode */
-
- regs.r[0] = sp_info.mode;
- regs.r[1] = VDU_Log2BPC;
-
- oserr_p = (os_error *) _kernel_swi ( OS_ReadModeVariable, ®s, ®s );
-
- if ( oserr_p ) do_os_error ( oserr_p );
-
- bpp = 1<<regs.r[2];
-
- if ( sp_h(sp_p).image != 44 ) bpp |= 0x100;
-
- return bpp;
- }
-
- /*******************************************************************************
-
- pre_process_sprite
-
- Given a pointer to the sprite area and sprite:
-
- 1: Set up the sprite id in *sprite_id_p;
- 2: Remove LH wastage from the sprite;
- 3: Get the height & width in pixels, the line length in words and the
- bits per pixel.
- 4: Unless a 256 colour sprite, extract palette in PCX form,
- using appropriate default if none stored with sprite.
-
- *******************************************************************************/
-
-
-
- void pre_process_sprite ( sprite_area * sp_area_p, sprite_ptr sp_p,
- sprite_id * sp_id_p,
- int * bpp, int * words,
- int * w, int * h, ubyte palette[] )
- {
- os_error * oserr_p;
- sprite_info sp_info;
- int i, colours, haspal;
- ubyte * src_pal_p;
-
- /* Set up sprite id */
-
- sp_id_p->s.addr = sp_p;
- sp_id_p->tag = sprite_id_addr;
-
- /* Left-align sprite */
-
- if ( oserr_p = sprite_removewastage ( sp_area_p, sp_id_p ) )
- do_os_error ( oserr_p );
-
- oserr_p = sprite_readsize ( sp_area_p, sp_id_p, &sp_info );
-
- if ( oserr_p ) do_os_error ( oserr_p );
-
- *bpp = get_bpp_and_pal ( sp_area_p, sp_p );
-
- haspal = (*bpp) & 0x100;
- *bpp &=0xff;
-
- colours = 1<<*bpp;
-
- /* Get the height & width of the sprite */
-
- *h = sp_info.height; *w = sp_info.width;
- *words = sp_h(sp_p).width + 1;
-
- /* Get the palette info */
-
- if (*bpp < 8)
- {
- if ( (!haspal) || force_pal )
- {
- /* default palette */
- src_pal_p = choose_palette(*bpp);
-
- for ( i=0; i< colours * 3; i++ ) palette[i] = *src_pal_p++;
- }
- else
- {
- src_pal_p = ((ubyte *) sp_p) + 40;
- for ( i=0; i < colours*3; i++ )
- {
- if ( i % 3 == 0 ) src_pal_p += 5; /* Skip over unwanted data */
- palette[i] = *src_pal_p++;
- }
- }
- }
- }
-
- /*******************************************************************************
-
- finfo - Get file information
-
- If called with len non-zero gets length of file into *len
-
- returns:
-
- -1 : Not found
- 0-0xFFF : File type for file found
- 0x1001 : Unstamped file found
- 0x1002 : Directory found
-
- *******************************************************************************/
-
- #define FINFO_ERR -1
- #define FINFO_DIR 0x1002
- #define FINFO_DATA 0x1001
-
- int finfo ( char * name, int * len )
- {
- _kernel_osfile_block fileinfo;
- int obtype;
-
- obtype = _kernel_osfile ( 17, name, & fileinfo );
-
- if ( len ) *len = fileinfo.start;
-
- if ( obtype==1 && (fileinfo.load & 0xFFF00000) == 0xFFF00000 )
- return (fileinfo.load & 0xFFF00) >> 8;
- else
- return obtype ? (obtype | 0x1000) : -1 ;
- }
-
- /*******************************************************************************
-
- Set type of named file to 12-bit type
-
- Return <>0 if error.
-
- *******************************************************************************/
-
- int settype ( char * file, int type )
- {
- _kernel_swi_regs regs;
- os_error * oserr_p;
-
- regs.r[0] = 18;
- regs.r[1] = (int) file;
- regs.r[2] = type;
- oserr_p = (os_error *) _kernel_swi ( OS_File, ®s, ®s );
- return oserr_p ? oserr_p->errnum : 0;
- }
-
- /*******************************************************************************
-
- Make directory. Return error number if failed
-
- *******************************************************************************/
-
- int mkdir ( char * dir )
- {
- _kernel_swi_regs regs;
- os_error * oserr_p;
-
- regs.r[0] = 8;
- regs.r[1] = (int) dir;
- regs.r[4] = 0;
- oserr_p = (os_error *) _kernel_swi ( OS_File, ®s, ®s );
- return oserr_p ? oserr_p->errnum : 0;
- }
-
-
- /*******************************************************************************
-
- int strisnum ( char * s )
-
- Returns true if string s is a valid number. Preceeding 0x signifies
- hex. You don't want to use octal, do you?
-
- *******************************************************************************/
-
- int strisnum ( char * s )
- {
- int len;
-
- len = strlen(s);
-
- if ( *s == '0' && tolower(s[1]) == 'x' )
- return ( strspn ( &s[2], "0123456789abcdefABCDEF" ) == len );
- else
- return ( strspn ( s, "0123456789" ) == len );
- }
-
- /*******************************************************************************
-
- sprite_ptr sprite_find ( sprite_area * sp_area_p, int number, char * name )
-
- Return pointer to required sprite in sprite area. If n>0, then find
- Nth sprite, otherwise find named sprite.
-
- If new_n_p is not null, number of sprite found is wriiten back.
-
- Returns null if not found
-
- *******************************************************************************/
-
- sprite_ptr sprite_find ( sprite_area * sp_area_p,
- int number, char * name, int * new_n_p )
- {
- char * cp1, * cp2;
- int found; int count;
-
- sprite_header * sp_h_p, * next_h_p;
-
- /* Silly case... */
-
- if ( number > sp_area_p->number ) return NULL;
-
- next_h_p = (sprite_header * ) ( ((int) sp_area_p) + sp_area_p->sproff );
-
- count = 0;
- cp1 = 0; cp2 = 0;
-
- do
- {
- sp_h_p = next_h_p;
-
- count++;
-
- if ( number )
- found = (count==number);
- else
- {
- for (
- cp1 = name, cp2 = sp_h_p->name;
- *cp1 && *cp2 && toupper(*cp1)==toupper(*cp2);
- cp1++, cp2++
- );
- found = (!*cp1) && (!*cp2);
- }
- next_h_p = (sprite_header *) ( ((int) sp_h_p) + sp_h_p->next );
-
- } while ( (!found) && count != sp_area_p->number );
-
- if ( found && new_n_p ) *new_n_p = count;
-
- return found ? (sprite_ptr) sp_h_p : NULL ;
- }
-
-