/* CrossFade : A video crossfade simulator (c) 1990 Dallas J. Hodgson Usage : CrossFade CrossFade takes 2 four-color ILBM pictures and smoothly crossfades between them, using nothing more than color register manipulation! The effect is similar to that used in pro video equipment, and lends itself to other applications such as animation, depth-arranging, etc. This idea could be extended to more bitplanes for extra colors or higher #'s of simultaneously-crossfadable images. HOW IT WORKS: CrossFade opens a 4-bitplane screen and loads each 4-color image into two bitplanes apiece. This results in a 16-color image, formed by the colors in image 1, (registers 0,1,2,3) image 2 (registers 0,4,8,12) and other color registers according to the overlap of bits between the two images. To blank out either image, we just set its color registers to the transparent color - almost. Wherever bits in bitplanes [0,1] (image 1) and [2,3] (image 2) overlap, other pencolors are formed from the overlap set { 5,6,7,9,10,11,13,14 }. These color registers have to be filled with redundant copies of the image colors we wish to display to prevent nasty XOR-type video effects. To explain this effect in all of its boolean detail would take up to much space. Screen-grab a CrossFaded display and manipulate the colors in DPaint - you'll see what I mean. Click on the window-close gadget in the upper left corner of the screen to exit. */ #include #include #include #include #include extern struct WBStartup *WBenchMsg; #define TITLE "CrossFade 1.0 : (c) 1990 John Hodgson\n" #define MAXWIDTH 376 /* max non-HIRES width */ #define MAXHEIGHT 242 /* max non-interlaced height */ #define MAXCOLORS 32 /* max # colors supported */ #define MakeID(a,b,c,d) ((a)<<24L | (b)<<16L | (c)<<8 | (d)) #define ID_FORM MakeID('F','O','R','M') #define ID_ILBM MakeID('I','L','B','M') #define ID_BMHD MakeID('B','M','H','D') #define ID_CAMG MakeID('C','A','M','G') #define ID_CMAP MakeID('C','M','A','P') #define ID_BODY MakeID('B','O','D','Y') #define cmpByteRun1 1 #define ROUNDODDUP(a) (((a)+1)&(~1L)) typedef struct { long ckID,ckSize; } Chunk; typedef struct { short w,h,x,y; char nPlanes,masking,compression,pad1; short transparentColor; char xAspect, yAspect; short pageWidth,pageHeight; } BitMapHeader; #define SafeRead(a,b,c) if (Read(a,b,c)==-1L) { Close(a); return(NULL); } void *IntuitionBase,*GfxBase; /************************************************************************ * * * Routine name(s) : ReadILBM() * * Author : D. John Hodgson * * Environment : Aztec "C", default * * * * ReadILBM attempts to read an IFF file and display it on a freshly * * opened custom screen. Returns a screen pointer if sucessful, * * otherwise NULL. * * * * LIMITATIONS : no masking, CATS/LISTS/PROPS. CAMG chunks supported. * ************************************************************************/ void *ReadILBM(fspec,size,bmhd,colormap,NewScreen) char *fspec; /* AmigaDOS filename */ long *size; /* size of allocated buffer */ BitMapHeader *bmhd; /* header for us to fill */ unsigned char colormap[MAXCOLORS][3]; /* colormap for us to fill */ struct NewScreen *NewScreen; /* screen struct for us to fill */ { struct Screen *screen; struct FileHandle *fp; char *sourcebuf; short i; long id,ViewModes=0; char *bufstart; Chunk header; setmem(bmhd,sizeof(*bmhd),0); /* start w/fresh structure */ if ((fp=Open(fspec,MODE_OLDFILE))==0) return(NULL); SafeRead(fp,&header,(long)sizeof(header)); if (header.ckID!=ID_FORM) { Close(fp); return(NULL); } SafeRead(fp,&id,(long)sizeof(id)); if (id!=ID_ILBM) { Close(fp); return(NULL); } for (;;) { SafeRead(fp,&header,(long)sizeof(header)); if (header.ckID==ID_BODY) break; switch(header.ckID) { case ID_BMHD: SafeRead(fp,bmhd,(long)sizeof(*bmhd)); break; case ID_CMAP: SafeRead(fp,&colormap[0][0],(long)header.ckSize); for (i=0;i>=4; break; case ID_CAMG: SafeRead(fp,&ViewModes,(long)header.ckSize); break; default: Seek(fp,ROUNDODDUP(header.ckSize),OFFSET_CURRENT); } } /* Read planes into RAM for ease of decompression */ sourcebuf=bufstart=AllocMem((long)header.ckSize,MEMF_PUBLIC); if (sourcebuf==0L) puts("Error allocating memory!"); *size=(long)header.ckSize; SafeRead(fp,sourcebuf,(long)header.ckSize); Close(fp); setmem(NewScreen,sizeof(*NewScreen),0); /* start fresh */ NewScreen->LeftEdge=0; NewScreen->TopEdge=0; NewScreen->Width=bmhd->w; NewScreen->Height=bmhd->h; NewScreen->Depth=bmhd->nPlanes; /* make some forced assumptions if CAMG chunk unavailable */ if (!(NewScreen->ViewModes=ViewModes)) { if (bmhd->w>MAXWIDTH) NewScreen->ViewModes|=HIRES; if (bmhd->h>MAXHEIGHT) NewScreen->ViewModes|=LACE; } NewScreen->Type=CUSTOMSCREEN; NewScreen->Font=0L; NewScreen->Gadgets=0L; return(bufstart); } Expand(screen,bmhd,sourcebuf,planeoffset) /* Fast line decompress/deinterleave */ struct Screen *screen; BitMapHeader *bmhd; register char *sourcebuf; short planeoffset; { register char n,*destbuf; /* in order of preferred allocation */ register short plane,linelen,rowbytes,i; linelen=bmhd->w/8; for (i=0;ih;i++) /* process n lines/screen */ for (plane=0;planenPlanes;plane++) { /* process n planes/line */ destbuf=(char *)(screen->BitMap.Planes[plane+planeoffset])+linelen*i; if (bmhd->compression==cmpByteRun1) { /* compressed screen? */ rowbytes=linelen; while (rowbytes) { /* unpack until 1 scan-line complete */ n=*sourcebuf++; /* fetch block run marker */ /* uncompressed block? copy n bytes verbatim */ if (n>=0) { movmem(sourcebuf,destbuf,(unsigned int)++n); rowbytes-=n; destbuf+=n; sourcebuf+=n; } else { /* compressed block? expand n duplicate bytes */ n=-n+1; rowbytes-=n; setmem(destbuf,(unsigned int)n,(unsigned int)*sourcebuf++); destbuf+=n; } } /* finish unpacking line */ } else { /* uncompressed? just copy */ movmem(sourcebuf,destbuf,(unsigned int)linelen); sourcebuf+=linelen; destbuf+=linelen; } } /* finish interleaved planes, lines */ } load_colormap(screen,colormap) struct Screen *screen; char colormap[MAXCOLORS][3]; { short i,colorcnt=1<BitMap.Depth; /* Sure, LoadRGB is faster, but uses UWORDS for its colors! */ for (i=0;iViewPort,(long)i, (long)colormap[i][0],(long)colormap[i][1], (long)colormap[i][2]); } } create_image1x4_colors(srcmap,dstmap) char srcmap[MAXCOLORS][3],dstmap[MAXCOLORS][3]; { short i,j; /* create image 1's color palette. Duplicates image 1 colors into the xx11 registers. */ for (i=0;i<16;i++) for (j=0;j<3;j++) dstmap[i][j]=srcmap[i%4][j]; } create_image2x4_colors(srcmap,dstmap) char srcmap[MAXCOLORS][3],dstmap[MAXCOLORS][3]; { short i,j; /* create image 2's color palette */ for (i=0;i<=4;i++) for (j=0;j<3;j++) dstmap[i*4][j]=srcmap[i][j]; /* Duplicate the image2 colors into the 11xx registers */ for (i=0;i<16;i++) { if (i%4) { for (j=0;j<3;j++) dstmap[i][j]=srcmap[(i & 0x0c)/4][j]; } } } FadeAtoB(screen,srcmap,dstmap) struct Screen *screen; char srcmap[MAXCOLORS][3],dstmap[MAXCOLORS][3]; { short i,j,flag,colorcnt=1<BitMap.Depth; do { flag=0; for (i=0;iUserPort)) { /* until CloseWindow */ FadeAtoB(screen,colormapA,colormapB); create_image1x4_colors(colormap1,colormapB); create_image2x4_colors(colormap2,colormapA); Delay(20); FadeAtoB(screen,colormapA,colormapB); create_image1x4_colors(colormap1,colormapA); create_image2x4_colors(colormap2,colormapB); } cleanup: if (buf1) FreeMem(buf1,size1); /* free compressed buffer */ if (buf2) FreeMem(buf2,size2); /* free compressed buffer */ if (window) CloseWindow(window); /* Intuition will ReplyMsg() for us */ if (screen) CloseScreen(screen); CloseLibrary(IntuitionBase); CloseLibrary(GfxBase); }