/* :bk=0 */ /****************************************************************************/ /* */ /* Dissolve.c */ /* */ /* Author: Lee M. Robertson */ /* Based on an article in the Nov '86 Doctor Dobb's Journal */ /* by Mike Morton */ /****************************************************************************/ #include "fcntl.h" #include "exec/types.h" #include "exec/memory.h" #include "graphics/copper.h" #include "graphics/gfx.h" #include "graphics/view.h" #include "graphics/rastport.h" #include "hardware/blit.h" #include "hardware/custom.h" #include "intuition/intuition.h" /*--------------------------------------------------------------------------- * following are definitions from the IFF specification *-------------------------------------------------------------------------*/ struct BitMapHeader { UWORD w, h; WORD x, y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE pad1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; }; typedef unsigned long ID; struct Chunk { ID ckID; long ckSize; }; struct ColorRegister { UBYTE red, green, blue; }; #define CSIZE sizeof(chunk) #define BMHDSIZE sizeof( struct BitMapHeader) #define mskNone 0 #define mskHasMask 1 #define mskHasTransparentColor 2 #define mskLasso 3 #define cmpNone 0 /* file is not compressed */ #define cmpByteRun1 1 /* file is Run Length Encoded */ #define MakeID(a,b,c,d) ( (long)(a)<<24 | (long)(b)<<16 | (long)(c)<<8 | (d) ) #define FORM MakeID('F','O','R','M') #define ILBM MakeID('I','L','B','M') #define LIST MakeID('L','I','S','T') #define BODY MakeID('B','O','D','Y') #define BMHD MakeID('B','M','H','D') #define CMAP MakeID('C','M','A','P') /*--------------------------------------------------------------------------- * Picture structure - this contains all the revalent data for a picture file *-------------------------------------------------------------------------*/ /* define for the # of bytes in the color register map */ #define CMSIZE 3*32 struct picture { int numcolors; /* # of valid colors */ int fd; /* the file # for this file */ struct BitMap *bm; /* a bitmap to store the picture */ long bodysize; /* # of bytes in the body data */ struct BitMapHeader bmhd; UBYTE cmap[CMSIZE]; /* the color values for this picture */ /* don't use the ColorRegister structure if using Aztec 'C' */ }; struct picture pic1,pic2; /* some picture sturcts */ struct BitMap BitMap; /* bitmap to read pictue into */ struct GfxBase *GfxBase; struct IntuitionBase *IntuitionBase; struct Window *Window; struct Screen *Screen; struct ViewPort *vp,*ViewPortAddress(); void *OpenLibrary(); void *GetMsg(); void *AllocMem(); void *OpenScreen(); void *OpenWindow(); #define INTUITION_REV 29L #define GRAPHICS_REV 29L struct NewWindow NewWindow = { 0, /* left edge */ 0, /* top edge */ 320, /* width */ 200, /* heigth */ 0,1, /* pen's */ /* IDCmpFlags */ RAWKEY | MOUSEBUTTONS | CLOSEWINDOW, /* flags */ RMBTRAP | WINDOWCLOSE | BACKDROP | NOCAREREFRESH | BORDERLESS | ACTIVATE, 0, /* gadget list */ 0, /* check mark */ 0, /* title pointer */ 0, /* screen pointer */ 0, /* bitmap pointer */ 0,0, /* minimum sizes */ 0,0, /* maximum sizes */ CUSTOMSCREEN, }; struct NewScreen NewScreen = { 0, /* left edge */ 0, /* top edge */ 320, /* width */ 200, /* heigth */ 5, /* depth */ 0,1, /* pen's */ 0, /* view modes */ CUSTOMSCREEN, /* type */ 0, /* font */ (UBYTE *)"Screen", /* title */ 0, /* gagets */ 0, /* bitmap */ }; /*--------------------------------------------------------------------------- * main() *-------------------------------------------------------------------------*/ main(argc,argv) int argc; char *argv[]; { char *open_pic(); char *rd_bmap(); char *errmsg; int speed; register int i; register long psize; /* the plane size in bytes */ register char *arg; register char *filename; if(argc < 2) { printf("Usage: Dissolve filename [ -# ]\n"); exit(0); } for( i=1; i < argc; i++ ) { argv++; arg = *argv; if( *arg == '-' ) speed = atoi( arg + 1 ); else filename = arg; } if( speed < 100 ) speed = 1000; open_libs(); /* open the libraries */ /* open the picture files */ if( errmsg = open_pic( filename, &pic1 )) { printf("%s: %s\n",errmsg,filename ); end( 10 ); } /* setup the temp bitmap for the data */ BitMap.BytesPerRow = (pic1.bmhd.w >> 4) << 1; BitMap.Rows = pic1.bmhd.h; BitMap.Depth = pic1.bmhd.nPlanes; psize = BitMap.BytesPerRow * BitMap.Rows; /* calculate the plane size */ if( psize == 0 || pic1.bmhd.nPlanes > 6 ) { printf("Ivalid parameters: %s\n",filename); end( 10 ); } NewScreen.Width = pic1.bmhd.w; NewScreen.Height = pic1.bmhd.h; NewScreen.Depth = pic1.bmhd.nPlanes; /* set bits for display modes */ if( NewScreen.Depth == 6 && NewScreen.Width <= 320 ) NewScreen.ViewModes |= HAM; if( NewScreen.Height > 200 ) NewScreen.ViewModes |= LACE; if( NewScreen.Width > 320 ) NewScreen.ViewModes |= HIRES; Screen = OpenScreen( &NewScreen); if( Screen == 0 ) { printf("Can't open Screen\n"); end(10); } NewWindow.Screen = Screen; NewWindow.Width = pic1.bmhd.w; NewWindow.Height = pic1.bmhd.h; Window = OpenWindow( &NewWindow ); if( Window == 0 ) { printf("Can't open Window\n"); end( 10 ); } ShowTitle( Screen, 0L ); /* hide the screen title */ vp = ViewPortAddress( Window ); /* get the windows viewport */ SetRast( Window->RPort, 0L ); /* clear the screen */ setcolors( vp, &pic1.cmap[0], pic1.numcolors ); errmsg = "No memory for BitMap"; /* Allocate memory for plane data */ for( i=0; iRPort->BitMap, speed) ) == 0 ) { while( get_message() == 0 ) WaitPort( Window->UserPort); } } nomem: for( i=0; i<8; i++) { if( BitMap.Planes[i] ) FreeMem( BitMap.Planes[i],psize ); } if( errmsg ) printf("%s: %s\n",errmsg,filename); end( 0 ); } /*--------------------------------------------------------------------------- * open_pic() -- open a picture file and initialize the picture data struct *-------------------------------------------------------------------------*/ char * open_pic( filename, pic ) char *filename; /* the picture file name */ register struct picture *pic; /* the picture data */ { register int fd; /* the picture file descriptor */ struct Chunk chunk; /* temp for read data */ register int cmsize; fd = open( filename, O_RDONLY); /* open the file */ if( fd == -1) return "Can't open"; if( read(fd, &chunk, CSIZE) != CSIZE ) goto readerr; if( chunk.ckID != FORM) return "Not a picture file"; /* check for ILBM file */ if( read(fd, &chunk, sizeof(long) ) != sizeof(long) ) goto readerr; if( chunk.ckID != ILBM ) return "Not an ILBM file"; if( read(fd, &chunk, CSIZE) != CSIZE ) goto readerr; if( chunk.ckID != BMHD) return "bit map header expected"; if( chunk.ckSize != BMHDSIZE ) return "Incorrect BMHD size"; /* read the BMHD data */ if( read( fd, &pic->bmhd, BMHDSIZE ) != BMHDSIZE ) goto readerr; pic->numcolors = 1; /* set default color map */ /* read chunks untill body is found */ while( read(fd, &chunk, CSIZE) == CSIZE ) { if( chunk.ckID == CMAP) { /* read the color map */ /* get size of the color map */ if( chunk.ckSize > CMSIZE ) cmsize = CMSIZE; else cmsize = chunk.ckSize; if( read(fd, &pic->cmap[0], cmsize ) != cmsize ) goto readerr; pic->numcolors = cmsize / 3; /* save # of colors in picture */ chunk.ckSize++; chunk.ckSize &= ~1; if( chunk.ckSize -= cmsize ) lseek( fd, chunk.ckSize, 1 ); /* skip rest of colormap */ } if( chunk.ckID == BODY ) { pic->bodysize = chunk.ckSize; pic->fd = fd; return 0; /* no errs */ } /* else ignore this chunks data */ lseek(fd,chunk.ckSize,1); } readerr: return "Read error"; } /*--------------------------------------------------------------------------- * open_libs() -- open the required libraries *-------------------------------------------------------------------------*/ open_libs() { if( !(IntuitionBase = OpenLibrary("intuition.library",INTUITION_REV)) ) { printf("Can't open Intuition library\n"); exit(5); } if( !(GfxBase = OpenLibrary("graphics.library",GRAPHICS_REV)) ) { printf("Can't open Graphics library\n"); CloseLibrary(IntuitionBase); exit(5); } } /*--------------------------------------------------------------------------- * end() -- cleanup and exit *-------------------------------------------------------------------------*/ end( err ) int err; { /* cleanup stuff */ if( Window ) CloseWindow( Window ); if( Screen ) CloseScreen( Screen ); if( GfxBase ) CloseLibrary(GfxBase); if( IntuitionBase ) CloseLibrary(IntuitionBase); exit( err ); } /*--------------------------------------------------------------------------- * setcolors() -- set the color registers *-------------------------------------------------------------------------*/ setcolors( vp, creg, numcolors ) struct ViewPort *vp; register UBYTE *creg; /* the color values */ int numcolors; /* the # of colors to set */ { register ULONG r,g,b; /* the RGB color values (temporaries) */ register int i; for(i=0; i> 4; g = *creg++ >> 4; b = *creg++ >> 4; SetRGB4( vp, (long)i, (long)r, (long)g, (long)b ); } } /*--------------------------------------------------------------------------- * *-------------------------------------------------------------------------*/ get_message() { register ULONG class; register USHORT code; register struct IntuiMessage *Message; static int retval = 0; while( Message = GetMsg(Window->UserPort) ) { class = Message->Class; code = Message->Code; ReplyMsg(Message); /* allow any key press to end program */ if( class == CLOSEWINDOW || class == RAWKEY ) retval = 1; /* allow user to hold program with right mouse button */ else if( class == MOUSEBUTTONS && code == MENUDOWN ) WaitPort( Window->UserPort); } return retval; } /*--------------------------------------------------------------------------- * rd_bmap() -- read a picture into a bitmap * This routine assumes the bitmap is the correct size to recieve * the picture. No error checking is done. *-------------------------------------------------------------------------*/ char *rd_bmap( bm, pic) struct BitMap *bm; struct picture *pic; { register UBYTE *buffer; /* the picture file data */ register UBYTE *data; register unsigned int i; register unsigned long size; register int nplanes; /* # of data planes */ UBYTE *planes[8]; /* array of pointers to plane data */ void *lmalloc(); char *error; if( !( buffer = lmalloc( pic->bodysize)) ) return "No Memory for body buffer"; error = 0; /* clear for return */ size = pic->bodysize; data = buffer; /* read the picture data */ while( size ) { if( size >= 0x10000 ) i = 0xffff; else i = size; if( read( pic->fd, data, i ) != i ) { error = "Read error"; goto err; } data += i; size -= i; } /* setup the data to pass to the decode routines */ nplanes = pic->bmhd.nPlanes; if( pic->bmhd.masking == mskHasMask ) nplanes++; /* add 1 for the mask plane */ for( i=0; i < 8; i++ ) planes[i] = bm->Planes[i]; /* copy plane pointers */ i = (pic->bmhd.w >> 4) << 1; /* # of bytes per row */ if( pic->bmhd.compression == cmpNone ) decode0( planes,buffer,i,pic->bmhd.h,nplanes); else if( pic->bmhd.compression == cmpByteRun1 ) decode1( planes,buffer,i,pic->bmhd.h,nplanes); else error = "Can't decode"; err: free( buffer ); /* dealloc the file data buffer */ return error; } /*--------------------------------------------------------------------------- * decode0() -- decodes the body data with no compression *-------------------------------------------------------------------------*/ decode0( planes,data,w,h,nplanes) UBYTE *planes[]; register UBYTE *data; register int w,h,nplanes; { register UBYTE **pp; /* pointer to current plane data */ register int pcnt; /* plane counter */ for( ; h; h--) /* for each row */ { for( pcnt = nplanes, pp = planes; pcnt; pcnt--, pp++ ) { if( *pp ) /* don't move the data if no destination plane */ { movmem( data, *pp, w); *pp += w; } data += w; } } } /*--------------------------------------------------------------------------- * decode1() -- decodes the body data with ByteRun1 compression * this should really be in assembly *-------------------------------------------------------------------------*/ decode1( planes,data,w,h,nplanes) UBYTE *planes[]; register BYTE *data; int w,h,nplanes; { register UBYTE **pp; /* pointer to current plane data */ register int pcnt; /* plane counter */ register int len; register int n; for( ; h; h--) /* for each row */ { for( pcnt = nplanes, pp = planes; pcnt; pcnt--, pp++ ) { for(n=w; n > 0; n -= len ) { len = *data++; if( len >= 0 ) { len++; if( *pp ) /* move the data if destination plane */ { movmem( data, *pp, len); *pp += len; } data += len; } else if( len != -128 ) /* ignore nop's */ { len = -len; len++; if( *pp ) /* move the data if destination plane */ { setmem( *pp, len, *data ); *pp += len; } data++; } else len = 0; /* if nop */ } } } } /*--------------------------------------------------------------------------- * some global variables for the dissolve function *-------------------------------------------------------------------------*/ unsigned long rand_mask; /* the mask value for the random # generator */ unsigned long rand_val; /* the current random # value */ unsigned long rand_tbl[] = /* the table of random mask values */ { /* from Nov '86 DDJ p. 48 */ 0,0, /* first 2 values don't work */ 3,6, 0xc,0x14, 0x30,0x60, 0xb8,0x110, 0x240,0x500, 0xca0,0x1b00, 0x3500,0x6000, 0xb400,0x12000, 0x20400,0x72000, 0x90000,0x140000, 0x300000,0x420000, 0xd80000,0x1200000, 0x3880000,0x7200000, 0x9000000,0x14000000, 0x32800000,0x48000000, 0xa3000000 /* for 32 bits wide */ }; /*--------------------------------------------------------------------------- * dissolve() -- dissolve one bitmap into another * this only works for full width bit maps *-------------------------------------------------------------------------*/ dissolve( src, dst, speed ) struct BitMap *src,*dst; int speed; { register UBYTE *mplane; /* the dissolve mask plane */ register long psize; /* the size of a plane */ register long nbits; /* # of bits in a plane */ register int done; psize = src->BytesPerRow * src->Rows; if( (mplane = AllocMem( psize, MEMF_CHIP | MEMF_CLEAR) ) == 0 ) return -1; nbits = psize << 3; nbits--; /* max bit is 1 less */ /* initialize the random number generator */ rand_val = 1; rand_mask = rand_tbl[ bitwidth(nbits) ]; mplane[0] |= 1; /* set the first bit in the mask plane */ done = 0; /* clear done flag */ while( done == 0 ) { done = setbits( mplane, nbits, speed ); BlitBitMapMask( src, dst, mplane ); if( get_message() ) break; } FreeMem( mplane, psize ); return 0; } /*--------------------------------------------------------------------------- * setbits() -- set random bits in a plane *-------------------------------------------------------------------------*/ setbits( plane, maxbit, numbits ) UBYTE *plane; unsigned long maxbit; unsigned int numbits; { #asm ;register useage: d5 - max bit # to set, d4 - random generator mask ; d3 - current random value, d2 - byte offset in array for bit ; d2 - bit # to set, d1 - loop counter regs reg d2-d5 movem.l regs,-(a7) move.l 8(a5),a0 ;get base address of array move.l 12(a5),d5 ;get maxbit number move 16(a5),d1 ;get # of bits to set move.l _rand_mask,d4 move.l _rand_val,d3 move.l #0,d0 ;clear ret val for not finished subq #1,d1 loop lsr.l #1,d3 ;rand_val >>= 1; bhi ok ;bif not 0 || no carry xor eor.l d4,d3 ;rand_val ^= rand_mask; ok cmp.l d5,d3 ;if( rand_val > maxbit ) bls setbit ;go set the bit if ok bra loop setloop lsr.l #1,d3 ;do the shift bls xor ;bif need to do the exculsive or setbit move.l d3,d2 ;copy to temp reg lsr.l #3,d2 ;make it a byte offset bset d3,0(a0,d2.l) ;set the bit in the array dbne d1,setloop ;end if bit is already set || # of bits done beq ret move.l #1,d0 ;set ret val for finished ret move.l d3,_rand_val ;save new random value movem.l (a7)+,regs #endasm } /*--------------------------------------------------------------------------- * bitwidth() -- get the # of bits in a long number *-------------------------------------------------------------------------*/ bitwidth( n ) register unsigned long n; { register int w; w = 0; while( n ) { w++; n >>= 1; } return w; } /*--------------------------------------------------------------------------- * *-------------------------------------------------------------------------*/