/* File: Dissolve.c Copyright 1990 by Thomas Knoll. Think C source file for Dissolve example. */ #include #include "FilterInterface.h" #define Length(string) (*(unsigned char *)(string)) typedef struct TParameters { short percent; } TParameters, *PParameters, **HParameters; short gResult; FilterRecordPtr gStuff; /*****************************************************************************/ /* Calls the host's TestAbort function */ Boolean TestAbort (void) { return CallPascalB (gStuff->abortProc); } /*****************************************************************************/ /* Calls the host's UpdateProgress procedure */ void UpdateProgress (done, total) long done; long total; { CallPascal (done, total, gStuff->progressProc); } /*****************************************************************************/ /* Centers a dialog template 1/3 of the way down on the main screen. */ void CenterDialog (dt) DialogTHndl dt; #define menuHeight 20 { Rect r; short width; short height; width = screenBits.bounds.right; height = screenBits.bounds.bottom; r = (**dt).boundsRect; OffsetRect (&r, -r.left, -r.top); OffsetRect (&r, (width - r.right) / 2, (height - r.bottom - menuHeight) / 3 + menuHeight); (**dt).boundsRect = r; } #undef menuHeight /*****************************************************************************/ /* Displays the about dialog box for the plug-in module. */ void DoAbout (void) #define dialogID 16000 { short item; DialogPtr dp; DialogTHndl dt; dt = (DialogTHndl) GetResource ('DLOG', dialogID); HNoPurge ((Handle) dt); CenterDialog (dt); dp = GetNewDialog (dialogID, nil, (WindowPtr) -1); ModalDialog (nil, &item); DisposDialog (dp); HPurge ((Handle) dt); } #undef dialogID /*****************************************************************************/ /* UserItem to outline the OK button in a dialog box. */ pascal void OutlineOK (dp, item) DialogPtr dp; short item; { Rect r; Handle h; short itemType; SetUpA4 (); item = OK; GetDItem (dp, item, &itemType, &h, &r); PenNormal (); PenSize (3, 3); InsetRect (&r, -4, -4); FrameRoundRect (&r, 16, 16); PenNormal (); RestoreA4 (); } /*****************************************************************************/ /* Asks the user for the plug-in filter module's parameters. Note that the image size information is not yet defined at this point. Also, do not assume that the calling program will call this routine every time the filter is run (it may save the data held by the parameters handle in a macro file). */ void DoParameters (void) #define dialogID 16001 #define hookItem 3 #define percentItem 4 { Rect r; long x; short j; Str255 s; Handle h; short item; DialogPtr dp; short itemType; DialogTHndl dt; Handle percentText; if (!gStuff->parameters) { gStuff->parameters = NewHandle ((long) sizeof (TParameters)); if (!gStuff->parameters) { gResult = memFullErr; return; } ((PParameters) *gStuff->parameters)->percent = 50; } dt = (DialogTHndl) GetResource ('DLOG', dialogID); HNoPurge ((Handle) dt); CenterDialog (dt); dp = GetNewDialog (dialogID, nil, (WindowPtr) -1); RememberA4 (); GetDItem (dp, hookItem, &itemType, &h , &r); SetDItem (dp, hookItem, itemType, (Handle) &OutlineOK, &r); GetDItem (dp, percentItem, &itemType, &percentText, &r); NumToString (((PParameters) *gStuff->parameters)->percent, s); SetIText (percentText, s); do { SelIText (dp, percentItem, 0, 32767); ModalDialog (nil, &item); if (item == OK) { GetIText (percentText, s); StringToNum (s, &x); if (x < 1 || x > 99) item = 0; for (j = 1; j <= Length (s); j++) if (s[j] < '0' || s[j] > '9') item = 0; if (item == 0) SysBeep (1); } } while (item != OK && item != Cancel); DisposDialog (dp); HPurge ((Handle) dt); if (item == Cancel) { gResult = 1; return; } ((PParameters) *gStuff->parameters)->percent = x; } #undef dialogID #undef hookItem #undef percentItem /*****************************************************************************/ /* Prepare to filter an image. If the plug-in filter needs a large amount of buffer memory, this routine should set the bufferSpace field to the number of bytes required. */ void DoPrepare (void) { } /*****************************************************************************/ /* Requests pointer to the first part of the image to be filtered. */ void DoStart (void) { gStuff->inRect = gStuff->filterRect; gStuff->inRect.bottom = gStuff->inRect.top + 1; gStuff->inLoPlane = 0; switch (gStuff->imageMode) { case filterModeGrayScale: gStuff->inHiPlane = 0; break; case filterModeRGBColor: case filterModeHSBColor: case filterModeHSLColor: gStuff->inHiPlane = 2; break; case filterModeCMYKColor: gStuff->inHiPlane = 3; break; default: gResult = filterBadMode; } gStuff->outRect = gStuff->inRect; gStuff->outLoPlane = gStuff->inLoPlane; gStuff->outHiPlane = gStuff->inHiPlane; } /*****************************************************************************/ /* Filters the area and requests the next area. */ void DoContinue (void) { short rand; short count; short plane; short percent; unsigned char *srcPtr; unsigned char *dstPtr; if (TestAbort ()) { gResult = 1; return; } UpdateProgress ((long) gStuff->inRect.top - gStuff->filterRect.top, (long) gStuff->filterRect.bottom - gStuff->filterRect.top); percent = ((PParameters) *gStuff->parameters)->percent; srcPtr = (unsigned char *) gStuff->inData; dstPtr = (unsigned char *) gStuff->outData; count = gStuff->filterRect.right - gStuff->filterRect.left; while (count--) { rand = Random (); rand = (rand < 0 ? -rand : rand); if (rand % 100 < percent) { for (plane = 0; plane <= gStuff->inHiPlane; plane++) *(dstPtr++) = gStuff->backColor [plane]; srcPtr += gStuff->planes; } else for (plane = 0; plane <= gStuff->inHiPlane; plane++) *(dstPtr++) = *(srcPtr++); } gStuff->inRect.top = gStuff->inRect.top + 1; gStuff->inRect.bottom = gStuff->inRect.bottom + 1; if (gStuff->inRect.top >= gStuff->filterRect.bottom) SetRect (&gStuff->inRect, 0, 0, 0, 0); gStuff->outRect = gStuff->inRect; } /*****************************************************************************/ /* This routine will always be called if DoStart does not return an error (even if DoContinue returns an error or the user aborts the operation). This allows the module to perform any needed cleanup. None is required in this example. */ void DoFinish (void) { } /*****************************************************************************/ /* Main dispatching routine. Initializes and sets up the global variables, and performs the operation specified by the selector. */ pascal void main (selector, stuff, data, result) short selector; FilterRecordPtr stuff; long *data; short *result; { /* Allow access to global variables */ RememberA0 (); SetUpA4 (); /* Copy the current quickdraw globals into the plug-in local copy */ asm { MOVE.L (A5),A0 ; Get address of real quickdraw globals SUB.L #126,A0 ; Move to start LEA randSeed,A1 ; Get address of local copy MOVE.W #64,D0 ; Globals are 65 words long @1 MOVE.W (A0)+,(A1)+ ; Copy a word DBF D0,@1 ; Move to next word } /* Perform the requested operation */ gStuff = stuff; gResult = noErr; switch (selector) { case filterSelectorAbout: DoAbout (); break; case filterSelectorParameters: DoParameters (); break; case filterSelectorPrepare: DoPrepare (); break; case filterSelectorStart: DoStart (); break; case filterSelectorContinue: DoContinue (); break; case filterSelectorFinish: DoFinish (); break; default: gResult = filterBadParameters; } *result = gResult; /* Restore the application's A4 register */ RestoreA4 (); }