/** dropshadow.c **/ /* this program copyright 1987, james mackraz. may not be distributed * for profit. copies of the source may be made for not-for-profit * distribution, but must include this notice. * * james mackraz, 4021 Second Street, Palo Alto, CA, 94306 */ #include "ds.h" #include #define printf kprintf UBYTE *wtitle = (UBYTE *) " DropShadow -- ver 2, rev 0 "; struct Window *getNewWind(); struct RastPort *rport2 = NULL; /* for rendering into bmap2 */ struct Window *window = NULL; struct Task *mytask; UBYTE mysig = 0; struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct LayersBase *LayersBase; ULONG flg = ACTIVATE | WINDOWCLOSE | NOCAREREFRESH | WINDOWDRAG | WINDOWDEPTH | SIMPLE_REFRESH; ULONG iflg = MOUSEMOVE | CLOSEWINDOW | GADGETDOWN | GADGETUP; /* for each layer, front to back, not incl. backdrops */ #define FORLAYERS(l, linfo) for (l = (linfo)->top_layer; \ l && !(l->Flags & LAYERBACKDROP);l=l->back) #define BACKTOFRONT(l) for (l = window->WLayer->LayerInfo->top_layer; \ l && l->back; l = l->back) ; \ for (; l; l = l->front) #define PREDLAYERS(pred, l) for (pred = l->front; pred; pred = pred->front) #define MYPRI 7L /* a little advantage */ #define INPUTPRI_PLUS 25L /* i guess i could findtask("input.device") */ USHORT hdrop = 7; USHORT vdrop = 3; main() { struct IntuiMessage *msg; /* hold data from *msg */ ULONG class; UBYTE code; struct Gadget *gaddress; struct Screen *wbscreen; struct BitMap *save_bitmap= NULL; /* original WB RasInfo bitmap */ struct BitMap *ribitmap = NULL; /* my 3-deep replacement */ struct BitMap *bmap2 = NULL; int i; int it_is_done = 0; /* success flag */ WORD exitval = 0; ULONG sigmask; ULONG sigtaken; extern struct PropInfo twxtinfo; USHORT twxtpot; if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0L))) { D( printf("NO INTUITION LIBRARY\n") ); exitval = 1; goto EXITING; } if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L))) { D( printf("NO GRAPHICS LIBRARY\n") ); exitval = 2; goto EXITING; } if (!(LayersBase=(struct LayersBase *) OpenLibrary("layers.library", 0L))) { D( printf("NO LAYERS LIBRARY\n") ); exitval = 2; goto EXITING; } /* get a window on the workbench */ window = getNewWind(120, 20, 400, 30, flg, iflg); if (window == NULL) { D( printf("test: can't get window.\n") ); exitval = 1; goto EXITING; } /* Add bitplane to the Workbench, as far as ViewPort is concerned */ wbscreen = window->WScreen; /* find it */ /* new 3-deep bitmap will replace the one in WB's RInfo */ if (!(ribitmap = (struct BitMap *) AllocMem((LONG) sizeof(struct BitMap), (LONG) MEMF_PUBLIC|MEMF_CLEAR))) { D( printf("alloc bitmap failed\n") ); goto EXITING; } InitBitMap(ribitmap, 3L, (LONG) wbscreen->Width, (LONG) wbscreen->Height); /* allocate bitmap for my rastport view of single bitplane */ if (!(bmap2 = (struct BitMap *) AllocMem((LONG) sizeof(struct BitMap), (LONG) MEMF_PUBLIC|MEMF_CLEAR))) { D( printf("alloc bitmap failed\n") ); goto EXITING; } /* my rendering bit map: depth 1 */ InitBitMap(bmap2, 1L, (LONG) wbscreen->Width, (LONG) wbscreen->Height); if (!(bmap2->Planes[0] = (UBYTE *) AllocRaster((LONG) wbscreen->Width, (LONG) wbscreen->Height))) { D( printf("alloc raster failed\n") ); goto EXITING; } /* get a rastport, and set it up for rendering into bmap2 */ if (!(rport2 = (struct RastPort *) AllocMem((LONG) sizeof (struct RastPort), (LONG) MEMF_PUBLIC))) { D( printf("alloc rastport failed\n") ); goto EXITING; } InitRastPort(rport2); rport2->BitMap = bmap2; SetRast(rport2, 0L); /* set up new bitmap for RInfo */ save_bitmap = wbscreen->ViewPort.RasInfo->BitMap; ribitmap->Planes[0] = save_bitmap->Planes[0]; ribitmap->Planes[1] = save_bitmap->Planes[1]; ribitmap->Planes[2] = bmap2->Planes[0]; Forbid(); /* add our extra plane to the bit-map as viewed by * the WB ViewPort (WB should never know the difference) */ wbscreen->ViewPort.RasInfo->BitMap = ribitmap; Permit(); it_is_done = 1; shadowColors(wbscreen); /* put viewport changed into effect */ MakeScreen(wbscreen); RethinkDisplay(); twxtpot = twxtinfo.HorizPot; hdrop = twxtpot >> TWXTSHIFT; vdrop = twxtpot >> (TWXTSHIFT + 1); drawShadow(); /* hook into the library vectors */ mytask = FindTask(0L); mysig = AllocSignal((LONG) -1); sigmask = ((LONG) 1 << mysig); sigmask |= ((LONG) 1 << window->UserPort->mp_SigBit); setup_hooks(); /* a little help */ SetTaskPri(mytask, MYPRI); FOREVER { if ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)) == NULL) { sigtaken = Wait(sigmask); if (sigtaken & ((LONG) 1 << mysig)) { drawShadow(); } continue; } class = msg->Class; code = msg->Code; gaddress = (struct Gadget *) msg->IAddress; ReplyMsg(msg); switch (class) { case MOUSEMOVE: /* taken at higher priority */ shadowColors(wbscreen); break; case GADGETDOWN: SetTaskPri(mytask, INPUTPRI_PLUS); break; case GADGETUP: SetTaskPri(mytask, MYPRI); switch (gaddress->GadgetID) { case TWIXTID: twxtpot = twxtinfo.HorizPot; hdrop = twxtpot >> TWXTSHIFT; vdrop = twxtpot >> (TWXTSHIFT + 1); drawShadow(); break; case DARKID: shadowColors(wbscreen); break; } break; case CLOSEWINDOW: SetTaskPri(mytask, 0L); if (cleanup_hooks()) goto EXITING; default: D( printf("unknown event: class %lx\n", class) ); } } EXITING: /* clean up trick */ if (it_is_done) { Forbid(); wbscreen->ViewPort.RasInfo->BitMap = save_bitmap; Permit(); MakeScreen(wbscreen); RethinkDisplay(); } if (mysig) FreeSignal((LONG) mysig); if (rport2) FreeMem(rport2, (LONG) sizeof (struct RastPort)); if (bmap2) { if (bmap2->Planes[0]) { FreeRaster(bmap2->Planes[0], (LONG) wbscreen->Width, (LONG) wbscreen->Height); } FreeMem(bmap2, (LONG) sizeof (struct BitMap)); } if (ribitmap) FreeMem(ribitmap, (LONG) sizeof (struct BitMap)); if (window) CloseWindow(window); if (GfxBase) CloseLibrary(GfxBase); if (LayersBase) CloseLibrary(LayersBase); if (IntuitionBase) CloseLibrary(IntuitionBase); exit (exitval); } /* returns true if this layer casts a shadow * note that menu layer does not cast a shadow */ shadowCaster(l) register struct Layer *l; { extern struct PropInfo darkinfo; register struct Window *w; register struct RastPort *brp; if (l && (w = (struct Window *) l->Window)) { /* must be border layer for GZZ window */ if (brp = w->BorderRPort) { /* GZZ */ return (brp->Layer == l); } else { /* non-GZZ */ return (l == w->WLayer); } } return (0); } /* called by my replacement layers vectors */ drawShadowSignal(sysret) LONG sysret; { Signal( mytask, ((LONG) 1 << mysig)); return (sysret); } /* run on my own task's schedule */ drawShadow(sysret) LONG sysret; { struct Region *shadow; if ( !(shadow = NewRegion()) ) return (sysret); bigShadow(shadow); SetRast(rport2, 0L); Forbid(); WaitBOVP(&window->WScreen->ViewPort); SetAPen(rport2, 1L); fillRegion(rport2, shadow); Permit(); DisposeRegion(shadow); } /* you want speed? speed this up. */ bigShadow(rgn) struct Region *rgn; { register struct Layer *pred; /* pred to 'l' */ register LONG tmprgn; /* accumulates shadow on layer 'l' */ register struct Layer *l; /* create all shadows on each layer */ int twixt; /* number of "spaces" between l, pred */ int htwixt; int vtwixt; struct Rectangle lrect; struct Rectangle predrect; if ( !(tmprgn = (LONG) NewRegion()) ) return; /* protect the integrity of the layer list */ LockLayerInfo(window->WLayer->LayerInfo); BACKTOFRONT(l) { /* could eliminate any layers you don't want a shadow on here. */ /* layer rectangle */ lrect = l->bounds; #if 0 notRectRegion(rgn, &lrect); /* l obscures shadows behind it */ #else ClearRectRegion(rgn, &lrect); /* dale's version */ #endif #if OLDTWIXT twixt = 0; #else htwixt = hdrop << 1; vtwixt = vdrop << 1; #endif ClearRegion(tmprgn); /* will build shadow on single layer */ /* walk through shadow casters */ PREDLAYERS(pred, l) { /* menu bar doesn't cast shadow */ if (!shadowCaster(pred)) { continue; } /* rectangle will cast shadow */ predrect = pred->bounds; /* layer rect */ /* shadow offset increases with depth */ #if OLDTWIXT translateRect(&predrect, HDROP + twixt * (HDROP >> 1), VDROP + twixt * (VDROP >> 1)); ++twixt; /* another level up */ #else translateRect(&predrect, htwixt, vtwixt); htwixt += hdrop; vtwixt += vdrop; #endif /* add it to accumulated shadow on 'l' */ OrRectRegion(tmprgn, &predrect); } /* all shadows on 'l' should actually be on 'l' */ AndRectRegion(tmprgn, &lrect); /* add shadows on l to shadows on layers behind l */ OrRegionRegion(tmprgn, rgn); } UnlockLayerInfo(window->WLayer->LayerInfo); DisposeRegion(tmprgn); } /* can use dale's ClearRectRegion */ #if 0 notRectRegion(rgn, rect) struct Region *rgn; struct Rectangle *rect; { OrRectRegion(rgn, rect); XorRectRegion(rgn, rect); } #endif /* this doesn't get use anymore */ #define GOODRECT(r) (((r)->MinX < (r)->MaxX) && ((r)->MinY < (r)->MaxY)) fillRegion(rp, rgn) struct RastPort *rp; struct Region *rgn; { register struct RegionRectangle *rgnrect; register struct Rectangle *bds; register int minx; /* offsets for all region rectangles */ register int miny; minx = rgn->bounds.MinX; miny = rgn->bounds.MinY; rgnrect = rgn->RegionRectangle; while (rgnrect) { bds = &rgnrect->bounds; RectFill(rp, (LONG)minx + bds->MinX, (LONG) miny + bds->MinY, (LONG) minx + bds->MaxX, (LONG) miny + bds->MaxY); rgnrect = rgnrect->Next; } } translateRect(r, dx, dy) register struct Rectangle *r; register int dx; register int dy; { r->MinX += dx; r->MaxX += dx; r->MinY += dy; r->MaxY += dy; } screenRect(s, r) register struct Screen *s; register struct Rectangle *r; { r->MaxX = (r->MinX = s->LeftEdge) + s->Width - 1; r->MaxY = (r->MinY = s->TopEdge) + s->Height - 1; } windowRect(w, r) register struct Window *w; register struct Rectangle *r; { r->MaxX = (r->MinX = w->LeftEdge) + w->Width - 1; r->MaxY = (r->MinY = w->TopEdge) + w->Height - 1; } struct Window * getNewWind(left, top, width, height, flg, iflg) SHORT left, top, width, height; ULONG flg, iflg; { extern struct Gadget darkness; struct Window *OpenWindow(); struct NewWindow nw; nw.LeftEdge = (SHORT) left; nw.TopEdge = (SHORT) top; nw.Width = (SHORT) width; nw.Height = (SHORT) height; nw.DetailPen = (UBYTE) -1; nw.BlockPen = (UBYTE) -1; nw.IDCMPFlags = (ULONG) iflg; nw.Flags = (ULONG) flg; nw.FirstGadget = (struct Gadget *) &darkness; nw.CheckMark = (struct Image *) NULL; nw.Title = (UBYTE *) wtitle; nw.Screen = (struct Screen *) NULL; nw.BitMap = (struct BitMap *) NULL; nw.MinWidth = (SHORT) 50; nw.MinHeight= (SHORT) 30; /* work around bug */ nw.MaxWidth = (SHORT) nw.Width; nw.MaxHeight = (SHORT) nw.Height; nw.Type = (USHORT) WBENCHSCREEN; return ((struct Window *) OpenWindow(&nw)); } #define DARKER(c) (((long) (((c) & 0xF) * (darkpot)) ) >> 16) shadowColors(s) struct Screen *s; { register int i; register ULONG rgb; ULONG red, green, blue; struct ColorMap *cm; USHORT darkpot; darkpot = darkinfo.HorizPot; cm = s->ViewPort.ColorMap; for (i = 0; i < 4; ++i) { /* get three colors */ rgb = GetRGB4(cm, (LONG) i); #if 0 rgb = ~rgb; /* wild colors, not wild enough */ #endif blue = DARKER(rgb); green = DARKER(rgb >>= 4); red = DARKER(rgb >> 4); SetRGB4(&s->ViewPort, (LONG) i + 4,(LONG) red,(LONG) green,(LONG) blue); } }