pictmovier.c

/*
  File:     PictMovier.c
  Contains: Application to make a movie from PICTs with various processes
  Written by:   Mark Krueger
  Copyright:    © 1990-1994 by Apple Computer, Inc., all rights reserved.
  Change History (most recent first):
  12/06/94          khs     Fixes for MW
  06/05/94          PM/MHK  New Today   
        
  This example shows how you can make movies by doing processing on pictures.
  This allows a process that takes a long time to be shown at much faster rates
  as a QuickTime movie. Any type of processing can be done, such as filtering, 
  transitions, 3-D transformations. This example shows two trivial examples.
  The first simple does a linear cross fade between two images. The second creates
  a random dot stereogram ( an image that if you stare at it long enough you can
  see three dimensional depth in ( without special glasses ). This works from a single
  image and shows how the effect can be varied from frame to frame.
  Note that the code is not necessarily well commented, but should prove useful as 
  a jumping off point for making your own movie creation applications.
*/
 
 
// INCLUDES
#include    <Types.h>
#include    <Files.h>
#include    <Quickdraw.h>
#include    <Packages.h>
#include    <Memory.h>
#include    <Fonts.h>
#include    <Events.h>
#include    <OSUtils.h>
#include    <ToolUtils.h>
#include    <Menus.h>
#include    <Dialogs.h>
#include    <stdio.h>
#include    <Errors.h>
#include    <Scrap.h>
#include    <Desk.h>
#include    <string.h>
#include    <GestaltEqu.h>
#include    <Resources.h>
#include    <Finder.h>
#include    <PictUtil.h>
#include    <palettes.h>
#include    <OSEvents.h>
#include    <Math.h>
#include    <SegLoad.h>
#include    <Windows.h>
 
 
#ifndef THINK_C
#include    <Strings.h>
#endif
 
#include    <ImageCompression.h>
#include    <QuickTimeComponents.h>
#include    <Components.h>
#include    <Movies.h>
 
 
// DEFINES
#define kNumberSteps  30
#define kFrameRate 10           /* frames per second */
#define kCodecID  anyCodec
#define kCodecType  (CodecType) 'rpza'
#define kCodecDepth 32
#define kCodecQuality  codecNormalQuality
 
 
// FUNCTION PROTOTYPES
void FixMenus(void);
void SetupMenus(void);
void Error(char* msg, OSErr code);
void ShowAboutBox(void);
void Initialize(void);
long DoClose(WindowPtr wind);
void SetCompression(void);
void SetStages(void);
void DoHLock(Handle h);
void DoHUnlock(Handle h);
void DoDisposHandle(Handle h);
void DoPreview(void);
void DoMovie(void);
void DoCopy(void);
void DoCut(void);
void DoPaste(void);
void DoClear(void);
void DoUndo(void);
Boolean HandleEvents(EventRecord* myEvent);
OSErr DoOpen(FSSpec* fsp);
long BetterRand(long reseed);
unsigned char DecodeDepth(unsigned char pix);
void DoCrossFade(long stageNum,
                 long totalStages,
                 Boolean reverse);
void DoRandomDotStereogram(long stageNum,
                           long totalStages,
                           Boolean reverse);
void DoStage(long stageNum,
             long totalStages,
             Boolean reverse);
void DoClear();
void DoUpdate(CWindowPtr wind);
short DoCommand(long mResult);
OSErr AllocateBuffers(void);
CWindowPtr MakeSWindow(Rect* frame,
                       StringPtr name,
                       GWorldPtr buffer);
 
 
// GLOBALS
CWindowPtr gSrcWindow = nil;
CWindowPtr gAltWindow = nil;
CWindowPtr gDstWindow = nil;
Rect gOriginalPicFrame;
Boolean gZoomed = false;
Boolean gFitToWindow = true;
Boolean gHasNewStdFile = false;
PicHandle gOriginalPicture = nil;
Boolean gCompressed = false;
GWorldPtr gWorld = nil;
GWorldPtr gAltWorld = nil;
GWorldPtr gDstWorld = nil;
GWorldPtr gBufferWorld = nil;
long gFrameNumber = -1;
MenuHandle gMenus[4];                           // our menus
Boolean gExitFlag = false;
WindowPtr gActiveWindow = nil;
Rect gRect;
 
short gStripWidth = 128;
short gDepthFactor = 16;
Boolean gDepthDecodeTabInted = false;
 
CodecType gCodecType = kCodecType;
CodecQ gCodecQuality = kCodecQuality;
CodecQ gCodecTemporalQuality = 0;
short gCodecDepth = kCodecDepth;
long gFrameRate = kFrameRate;
long gKeyFrameRate = kFrameRate;
CodecComponent gCodecID = kCodecID;
 
long gNumberSteps = kNumberSteps;
 
 
 
Boolean gOversample = false;
 
Boolean gBackwards = false;
 
#define     APPLE_MENU  0
#define     APPLE_MENU_ID   128
 
#define     FILE_MENU   1
#define     FILE_MENU_ID    129
 
#define     FILE_M_OPEN 1
#define     FILE_M_CLOSE 2
#define     FILE_M_SAVE 3
#define     FILE_M_QUIT 5
 
 
#define     EDIT_MENU   2
#define     EDIT_MENU_ID    130
#define     EDIT_M_UNDO     1
#define     EDIT_M_CUT      3
#define     EDIT_M_COPY     4
#define     EDIT_M_PASTE    5
#define     EDIT_M_CLEAR    6
 
#define     MOVIE_MENU  3
#define     MOVIE_MENU_ID   131
 
#define     MOVIE_M_COMPRESS    1
#define     MOVIE_M_STAGES      2
#define     MOVIE_M_OVERSAMPLE  3
#define     MOVIE_M_BACKWARDS   4
#define     MOVIE_M_PREVIEW     6
#define     MOVIE_M_MOVIE       8
 
 
Boolean gDoCrossFade = true;                    // type of processing to do ( set for crossfade, set to false to do random dot stereograms )
 
 
Boolean gRequiresAlternate = true;              // if true means requires second picture for processing
 
 
short gDepth = 32;                              // pixel depth of allocated image buffers
 
 
 
 
 
 
/*********************************************
  Funtion prototypes.
*/
 
 
 
/*********************************************
  Clean up menu hiliting
*********************************************/
 
void FixMenus(void)
{
    Boolean gotAllWindows = gSrcWindow != nil && (!gRequiresAlternate || gAltWindow != nil);
    Boolean gotAnyWindows = gSrcWindow != nil || gAltWindow != nil;
 
    DisableItem(gMenus[FILE_MENU], FILE_M_SAVE);
    if (gotAnyWindows)
        EnableItem(gMenus[FILE_MENU], FILE_M_CLOSE);
    else
        DisableItem(gMenus[FILE_MENU], FILE_M_CLOSE);
 
    if (gotAllWindows)
        DisableItem(gMenus[FILE_MENU], FILE_M_OPEN);
    else
        EnableItem(gMenus[FILE_MENU], FILE_M_OPEN);
 
    if (!gotAllWindows)
    {
        DisableItem(gMenus[MOVIE_MENU], MOVIE_M_MOVIE);
        DisableItem(gMenus[MOVIE_MENU], MOVIE_M_PREVIEW);
        DisableItem(gMenus[MOVIE_MENU], MOVIE_M_OVERSAMPLE);
    }
    else
    {
        EnableItem(gMenus[MOVIE_MENU], MOVIE_M_MOVIE);
        EnableItem(gMenus[MOVIE_MENU], MOVIE_M_PREVIEW);
        EnableItem(gMenus[MOVIE_MENU], MOVIE_M_OVERSAMPLE);
    }
 
    DisableItem(gMenus[EDIT_MENU], EDIT_M_CUT);
    DisableItem(gMenus[EDIT_MENU], EDIT_M_COPY);
    DisableItem(gMenus[EDIT_MENU], EDIT_M_PASTE);
 
    DisableItem(gMenus[EDIT_MENU], EDIT_M_CLEAR);
    DisableItem(gMenus[EDIT_MENU], EDIT_M_UNDO);
    CheckItem(gMenus[MOVIE_MENU], MOVIE_M_OVERSAMPLE, gOversample);
    CheckItem(gMenus[MOVIE_MENU], MOVIE_M_BACKWARDS, gBackwards);
}
 
 
/*********************************************
  Initialize menu bar.
*********************************************/
 
void SetupMenus(void)
{
 
    gMenus[APPLE_MENU] = GetMenu(APPLE_MENU_ID);
    AddResMenu(gMenus[APPLE_MENU], (ResType)'DRVR');
    InsertMenu(gMenus[APPLE_MENU], 0);
    gMenus[FILE_MENU] = GetMenu(FILE_MENU_ID);
    InsertMenu(gMenus[FILE_MENU], 0);
    gMenus[EDIT_MENU] = GetMenu(EDIT_MENU_ID);
    InsertMenu(gMenus[EDIT_MENU], 0);
    gMenus[MOVIE_MENU] = GetMenu(MOVIE_MENU_ID);
    InsertMenu(gMenus[MOVIE_MENU], 0);
    DrawMenuBar();
    FixMenus();
}
 
 
/*********************************************
  Prepare for work.
*********************************************/
 
 
void Initialize(void)
{
    Ptr size;
    long resp;
 
    size = GetApplLimit();
    SetApplLimit(size - 32 * 1024);             /* make room on stack so Quickdraw can do big pictures */
    MaxApplZone();
 
    /*  initialize managers */
 
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    InitDialogs(nil);
    InitCursor();
    FlushEvents(everyEvent, 0);
    SetupMenus();
    CouldAlert(140);
 
    if (NGetTrapAddress(0xab1d, ToolTrap) == NGetTrapAddress(0x9f, ToolTrap))
    {
        ExitToShell();
    }
    if (Gestalt(gestaltQuickTime, &resp) != 0)
    {
        ExitToShell();
    }
 
}
 
 
/*********************************************
  If some kind of fatal error happened come here.
*********************************************/
 
void Error(char* msg,
           OSErr code)
{
    char buf[256];
 
    GWorldPtr saveWorld;
    GDHandle saveGD;
    CGrafPtr wmgrPort;
 
    GetGWorld(&saveWorld, &saveGD);
    GetCWMgrPort(&wmgrPort);
    SetGWorld(wmgrPort, nil);
    if (code)
    {
        sprintf(buf, "%s %d", msg, code);
        msg = buf;
    }
    c2pstr(msg);
    ParamText((StringPtr)msg, "\p", 0, 0);
    if (code == 0)
        Alert(140, nil);
    else
        StopAlert(140, nil);
    SetGWorld(saveWorld, saveGD);
}
 
 
void ShowAboutBox(void)
{
 
    ParamText("\pPictMovier", "\pQuickTime!", 0, 0);
    Alert(140, nil);
}
 
 
/*
  Close a window
*/
 
 
long DoClose(WindowPtr wind)
{
 
    if (wind == nil)
        return (0);
    if (gActiveWindow == wind)
        gActiveWindow = nil;
 
    if (wind == (WindowPtr)gSrcWindow)
    {
        DoClear();
        gSrcWindow = nil;
        DisposeGWorld(gWorld);
        gWorld = nil;
    }
    else if (wind == (WindowPtr)gAltWindow)
    {
        DoClear();
        gAltWindow = nil;
        DisposeGWorld(gAltWorld);
        gAltWorld = nil;
    }
    else if (wind == (WindowPtr)gDstWindow)
    {
        gDstWindow = nil;
    }
    CloseWindow(wind);
    return (0);
 
}
 
 
 
/*********************************************
  Allow the user to set the compression parameters with the standard compression dialog.
*********************************************/
 
void SetCompression(void)
{
    ComponentInstance ci;
    Point where;
    SCParams p;
 
 
    where.h = where.v = -2;
    ci = OpenDefaultComponent('scdi', 0);
    if (ci == nil)
    {
        Error("Couldn't open StdCompression", 0);
        return;
    }
 
    p.flags = scShowMotionSettings;
    p.theCodecType = gCodecType;
    p.theCodec = gCodecID;
    p.spatialQuality = gCodecQuality;
    p.temporalQuality = gCodecTemporalQuality;
    p.depth = gCodecDepth;
    p.frameRate = gFrameRate << 16;
    p.keyFrameRate = gKeyFrameRate;
 
    SCGetCompressionExtended(ci, &p, where, 0,0,0,0);
 
    gCodecType = p.theCodecType;
    gCodecQuality = p.spatialQuality;
    gCodecTemporalQuality = p.temporalQuality;
    gCodecDepth = p.depth;
    gFrameRate = p.frameRate >> 16;
    gKeyFrameRate = p.keyFrameRate;
    gCodecID = p.theCodec;
}
 
 
/*
  Allow the user to set the number of stages she wants the processing to take.
*/
 
void SetStages(void)
{
 
 
#define STAGE_DLOG  128
#define IT_STAGES   3
#define IT_LINEAR   4
#define IT_OK   1
#define IT_CANCEL   2
 
    CGrafPtr savePort;
    DialogPtr theDialog;
    short itemType;
    Handle itemHdl;
    Rect itemRect;
    short itemHit,
     lastItem = -1;
    Boolean done = false;
    Point tp;
    GDHandle saveGD;
    Str255 text;
    long num;
    long stageCount = gNumberSteps;
    Boolean linear = true;
 
    if ((theDialog = GetNewDialog(STAGE_DLOG, nil, (WindowPtr) - 1)) == nil)
        return;
 
    GetMouse(&tp);
    GetGWorld(&savePort, &saveGD);
    SetPort(theDialog);
    GetDItem(theDialog, IT_OK, &itemType, &itemHdl, &itemRect);
    PenSize(3, 3);
    InsetRect(&itemRect, -4, -4);
    FrameRoundRect(&itemRect, 16, 16);
 
 
    GetDItem(theDialog, IT_STAGES, &itemType, &itemHdl, &itemRect);
 
    sprintf((char*)text, "%ld", stageCount);
    c2pstr((char*)text);
    SetIText(itemHdl, text);
 
    SelIText(theDialog, IT_STAGES, 0, 32767);
 
    GetDItem(theDialog, IT_LINEAR, &itemType, &itemHdl, &itemRect);
    SetCtlValue((ControlHandle)itemHdl, linear);
    HiliteControl((ControlHandle)itemHdl, 255);
 
    while (!done)
    {
        ModalDialog(nil, &itemHit);
        if (itemHit != lastItem)
        {
            switch (lastItem)
            {
                case IT_STAGES:
                    GetDItem(theDialog, IT_STAGES, &itemType, &itemHdl, &itemRect);
                    GetIText(itemHdl, text);
                    p2cstr(text);
                    if (sscanf((char*)text, "%ld", &num) == 1 && num > 0)
                        stageCount = num;
                    else
                        SysBeep(1);
                    sprintf((char*)text, "%ld", stageCount);
                    c2pstr((char*)text);
                    SetIText(itemHdl, text);
                    break;
            }
            lastItem = itemHit;
        }
        switch (itemHit)
        {
            case IT_OK:
                gNumberSteps = stageCount;
                done = true;
                break;
            case IT_CANCEL:
                done = true;
                break;
            case IT_LINEAR:
                linear =!linear;
                GetDItem(theDialog, IT_LINEAR, &itemType, &itemHdl, &itemRect);
                SetCtlValue((ControlHandle)itemHdl, linear);
                break;
            default:
                break;
        }
    }
    CloseDialog(theDialog);
    SetGWorld(savePort, saveGD);
}
 
 
void DoStage(long stageNum,
             long totalStages,
             Boolean reverse)
{
 
 
    if (gDoCrossFade)
        DoCrossFade(stageNum, totalStages, reverse);
    else
        DoRandomDotStereogram(stageNum, totalStages, reverse);
}
 
 
 
/*********************************************
  This processing routine creates a random dot stereogram of the input picture.
  The second picture is not used.
********************************************/
 
 
 
 
 
void DoRandomDotStereogram(long stageNum,
                           long totalStages,
                           Boolean reverse)
{
 
 
    /* StdFile stuff */
 
    CGrafPtr savePort;
    GDHandle saveGD;
    char* ip,
    * rp,
    * pp,
    * opp,
    * qp;
    char* sip,
    * srp,
    * spp;
    short rowBytes;
    short sRowBytes;
    char mode = 1;
 
    /* for sepecifying compression */
 
    short i,
     j,
     x,
     y,
     height,
     width;
    unsigned char pix,
     spix,
     ppix,
     qpix;
 
    char* lineBuf = nil;
    char* newLineBuf = nil;
    char* tLineBuf = nil;
#ifdef RDS_NEW_SEED_EACH_FRAME 
    unsigned long timeseed;
#endif
 
    //#define   RDS_DEPTH_FACTOR_VARIES         // set this to increase depth as movie progresses
 
    //#define   RDS_STRIP_WIDTH_VARIES          // set this to increase repeat strip as movie progresses
 
    //#define   RDS_NEW_SEED_EACH_FRAME         // set this to have a new random background for each frame 
 
 
 
#ifdef  RDS_NEW_SEED_EACH_FRAME
    GetDateTime(&timeseed);
    BetterRand(time);
#else
    BetterRand(1);
#endif
 
#ifdef  RDS_DEPTH_FACTOR_VARIES
    gDepthFactor = 1 + (stageNum * 64) / totalStages;
    gDepthDecodeTabInted = false;
#else
    gDepthFactor = 16;
#endif
 
#ifdef  RDS_STRIP_WIDTH_VARIES
    gStripWidth = 32 + (stageNum * 256) / totalStages;
 
#else
    gStripWidth = 128;
#endif
 
    GetGWorld(&savePort, &saveGD);
    SetGWorld(gDstWorld, nil);
    EraseRect(&gDstWorld->portRect);
    width = gWorld->portRect.right - gWorld->portRect.left;
    height = gWorld->portRect.bottom - gWorld->portRect.top;
    LockPixels(gWorld->portPixMap);
    sRowBytes = (*gWorld->portPixMap)->rowBytes & 0x7fff;
    sip = GetPixBaseAddr(gWorld->portPixMap);
    SetGWorld(gDstWorld, nil);
 
    LockPixels(gDstWorld->portPixMap);
    rowBytes = (*gDstWorld->portPixMap)->rowBytes & 0x7fff;
    ip = GetPixBaseAddr(gDstWorld->portPixMap);
 
 
    lineBuf = NewPtr(sRowBytes);
    if (lineBuf == nil)
    {
        Error("allocating line buffer", 0);
        goto done;
    }
    newLineBuf = NewPtr(rowBytes);
    if (newLineBuf == nil)
    {
        Error("allocating nline buffer", 0);
        goto done;
    }
    tLineBuf = NewPtr(sRowBytes);
    if (tLineBuf == nil)
    {
        Error("allocating tline buffer", 0);
        goto done;
    }
    SwapMMUMode(&mode);
    if (gDepth == 1)
    {
 
        rp = ip;
        for (y = 0; y < height; y++)
        {
            pp = rp;
            for (x = 0; x < gStripWidth / 8; x++, pp++)
            {
                pix = 0;
                for (i = 0; i < 8; i++)
                {
                    pix <<= 1;
                    if (BetterRand(0) % 5 == 0)
                        pix |= 1;
                }
                qp = pp;
                for (j = 0; j < width / gStripWidth; j++)
                {
                    *qp = pix;
                    qp += gStripWidth / 8;
                }
            }
            rp += rowBytes;
        }
        rp = ip;
        srp = sip;
 
 
        for (y = 0; y < height; y++)
        {
            pp = rp;
            spp = srp;
            spp += gDepthFactor / 8;
            qp = pp;
            BlockMove(pp, tLineBuf, sRowBytes);
            qp = tLineBuf;
            pp = qp;
            qp += gDepthFactor / 8;
 
            opp = newLineBuf;
            for (x = 0; x < width / 8 - gStripWidth / 8; x++, pp++, qp++, opp++)
            {
                spix = *spp++;
                qpix = *qp;
                ppix = *pp;
                pix = 0;
                for (i = 0; i < 8; i++)
                {
                    pix <<= 1;
                    if ((spix & 0x80))
                        pix |= (qpix & 0x80) != 0 ? 1 : 0;
                    else
                        pix |= (ppix & 0x80) != 0 ? 1 : 0;
                    spix <<= 1;
                    ppix <<= 1;
                    qpix <<= 1;
                }
                *opp = pix;
                *(pp + gStripWidth / 8) = pix;
            }
            BlockMove(newLineBuf, rp + gStripWidth / 8, rowBytes - gStripWidth / 8);
            rp += rowBytes;
            srp += sRowBytes;
        }
    }
    else if (gDepth == 8 || gDepth == 40)
    {
 
        rp = ip;
 
        for (y = 0; y < height; y++)
        {
            pp = rp;
            for (x = 0; x < gStripWidth; x++)
            {
                *pp++ = BetterRand(0);
            }
            rp += rowBytes;
        }
 
        rp = ip;
        srp = sip;
 
        for (y = 0; y < height; y++)
        {
            pp = rp;
            spp = srp;
            spp += gStripWidth;
 
            qp = pp;
            BlockMove(pp, tLineBuf, sRowBytes);
            qp = tLineBuf;
            pp = qp;
 
            opp = newLineBuf;
            for (x = 0; x < width - gStripWidth; x++, pp++, qp++, opp++)
            {
                spix = *spp++;
                ppix = *pp;
 
                pix = *(qp + DecodeDepth(spix));
                *opp = pix;
                *(pp + gStripWidth) = pix;
            }
            BlockMove(newLineBuf, rp + gStripWidth, rowBytes - gStripWidth);
            rp += rowBytes;
            srp += sRowBytes;
        }
    }
    SwapMMUMode(&mode);
    UnlockPixels(gDstWorld->portPixMap);
 
    SetGWorld(savePort, saveGD);
done:if (newLineBuf)
        DisposPtr(newLineBuf);
    if (lineBuf)
        DisposPtr(lineBuf);
    if (tLineBuf)
        DisposPtr(tLineBuf);
 
 
}
 
/*********************************************
  a better random function than the one in the ROM 
*********************************************/
 
long BetterRand(long reseed)
{
#define A   16807
#define M   2147483647
#define Q   127773
#define R   2836
 
    static long seed = 1;
 
    long lo,
     hi,
     test;
 
    if (reseed != 0)
        seed = reseed;
    hi = seed / Q;
    lo = seed % Q;
    test = A * lo - R * hi;
    if (test > 0)
        seed = test;
    else
        seed = test + M;
    return (seed / (M >> 16));
}
 
 
unsigned char DecodeDepth(unsigned char pix)
 
{
 
    static unsigned char table[256];
    short i;
 
    if (!gDepthDecodeTabInted)
    {
        gDepthDecodeTabInted = 1;
        for (i = 0; i < 255; i++)
        {
            table[i] = (i * gDepthFactor) / 255;
        }
    }
    return (table[pix]);
 
}
 
 
 
/*********************************************
  This processing routine does a linear cross dissolve between the two images,
  using CopyBits with blend mode. It shows how to do a process which involves 
  both images. Any type of process could be done here, using the three parameters
  to determine how much of the processing has progressed.
  Note: See the Develop article by Konstantin Othmar ( sorry I forget the issue number )
  about CopyBits to learn how to do other cool effects just using CopyBits.
*********************************************/
 
 
 
void DoCrossFade(long stageNum,
                 long totalStages,
                 Boolean reverse)
{
    GWorldPtr saveWorld;
    GDHandle saveGD;
    RGBColor opColor;
 
 
    if (reverse)
        opColor.red = opColor.green = opColor.blue = (stageNum * 0xffff) / totalStages;
    else
        opColor.red = opColor.green = opColor.blue = ((totalStages - stageNum) * 0xffff) / totalStages;
 
    GetGWorld(&saveWorld, &saveGD);
 
    SetGWorld(gDstWorld, nil);
    CopyBits((BitMap *) * gAltWorld->portPixMap, (BitMap *) * gDstWorld->portPixMap, &gAltWorld->portRect, &gDstWorld->portRect, ditherCopy, nil);
    OpColor(&opColor);
    CopyBits((BitMap *) * gWorld->portPixMap, (BitMap *) * gDstWorld->portPixMap, &gWorld->portRect, &gDstWorld->portRect, blend, nil);
    SetGWorld(saveWorld, saveGD);
 
}
 
 
/* 
  The following three routines are here because the MPW 3.2 c compiler 
  screw up compiling the DoMovie routine if you use the "straight" calls.
  Try it and see and complain to DTS.
*/
 
 
void DoHLock(Handle h)
{
    HLock(h);
}
 
 
void DoHUnlock(Handle h)
{
    HUnlock(h);
}
 
 
void DoDisposHandle(Handle h)
{
    DisposHandle(h);
}
 
/*********************************************
  Show a preview of some stage in the process.
********************************************/
 
 
void DoPreview(void)
{
 
 
#define PV_DLOG 129
#define IT_STAGE    4
#define IT_OK   1
#define IT_CANCEL   2
 
    CGrafPtr savePort;
    DialogPtr theDialog;
    short itemType;
    Handle itemHdl;
    Rect itemRect;
    short itemHit,
     lastItem = -1;
    Boolean done = false;
    Point tp;
    GDHandle saveGD;
    Str255 text;
    long num;
    long whichStage = gNumberSteps / 2;
 
 
    if ((theDialog = GetNewDialog(PV_DLOG, nil, (WindowPtr) - 1)) == nil)
        return;
 
    GetMouse(&tp);
    GetGWorld(&savePort, &saveGD);
    SetPort(theDialog);
    GetDItem(theDialog, IT_OK, &itemType, &itemHdl, &itemRect);
    PenSize(3, 3);
    InsetRect(&itemRect, -4, -4);
    FrameRoundRect(&itemRect, 16, 16);
 
 
    GetDItem(theDialog, IT_STAGE, &itemType, &itemHdl, &itemRect);
 
    sprintf((char*)text, "%ld", whichStage);
    c2pstr((char*)text);
    SetIText(itemHdl, text);
 
    SelIText(theDialog, IT_STAGE, 0, 32767);
 
    while (!done)
    {
        ModalDialog(nil, &itemHit);
        if (itemHit != lastItem)
        {
            switch (lastItem)
            {
                case IT_STAGE:
                    GetDItem(theDialog, IT_STAGE, &itemType, &itemHdl, &itemRect);
                    GetIText(itemHdl, text);
                    p2cstr(text);
                    if (sscanf((char*)text, "%ld", &num) == 1 && num > 0 && num <= gNumberSteps)
                        whichStage = num;
                    else
                        SysBeep(1);
                    sprintf((char*)text, "%ld", whichStage);
                    c2pstr((char*)text);
                    SetIText(itemHdl, text);
                    break;
            }
            lastItem = itemHit;
        }
        switch (itemHit)
        {
            case IT_OK:
                done = true;
                break;
            case IT_CANCEL:
                whichStage = 0;
                done = true;
                break;
            default:
                break;
        }
    }
    CloseDialog(theDialog);
 
    if (whichStage)
    {
 
        Rect rect;
 
        sprintf((char*)text, "Preview %d of %d", whichStage, gNumberSteps);
        c2pstr((char*)text);
 
        rect = gSrcWindow->portRect;
        SetGWorld(gSrcWindow, nil);
        LocalToGlobal((Point *) & rect.top);
        LocalToGlobal((Point *) & rect.bottom);
        OffsetRect(&rect, 20, 20);
        if (gOversample)
        {
            rect.right = rect.left + (rect.right - rect.left) / 2;
            rect.bottom = rect.top + (rect.bottom - rect.top) / 2;
        }
        SetGWorld(savePort, saveGD);
        if (gDstWindow)
        {
            CloseWindow((WindowPtr)gDstWindow);
            gDstWindow = nil;
        }
        if ((gDstWindow = (CWindowPtr)NewCWindow(nil, &rect, text, true, zoomDocProc, (WindowPtr) - 1, true, 0)) == nil)
        {
            Error("NewCWindow Failed", 0);
            goto done;
        }
        BringToFront((WindowPtr)gDstWindow);
        HiliteWindow((WindowPtr)gDstWindow, true);
        SetGWorld((CGrafPtr)gDstWorld, nil);
        PaintRect(&gDstWorld->portRect);
 
 
        if (gDstWorld && gWorld && gAltWorld)
            DoStage(whichStage, gNumberSteps, gBackwards);
 
        SetGWorld((CGrafPtr)gDstWindow, nil);
        CopyBits((BitMap *) * gDstWorld->portPixMap, (BitMap *) * gDstWindow->portPixMap, &gDstWorld->portRect, &gDstWindow->portRect, ditherCopy, nil);
    }
done:SetGWorld(savePort, saveGD);
}
 
 
/*********************************************
  Create the movie by processing all the frames.
********************************************/
 
 
void DoMovie(void)
 
{
    GWorldPtr saveWorld;
    GDHandle saveGD;
    short resRefNum;
    OSErr result;
    Rect rect;
 
    /* Stuff for creating the file */
 
    Point dlgPos =
    {
        100,  100
    }
    ;                                           /* Position the dialog box */
    SFReply sfr;                                /* StdFile reply */
    FSSpec mySpec;                              /* Data structure with filename, etc. */
    Movie gMovie = 0;                           /* Our movie, track and media */
    Track gTrack;
    Media gMedia;
    long maxCompressedFrameSize;                /* Max size of compressed frame     */
    long compressedFrameSize;                   /* Size of current compressed frame */
    Handle compressedFrameBitsH = nil;          /* Buffer for the compressed data   */
    ImageDescription * *imageDescriptionH = nil;/* Contains info about the sample   */
    Ptr data;
    EventRecord myEvent;
    ImageSequence seq;
    static Str255 name = "\pMy Movie";
    Rect dstRect;
    short width,
     height;
    TimeValue timeVal;
 
 
 
    if (gDstWindow)
    {
        CloseWindow((WindowPtr)gDstWindow);
        gDstWindow = nil;
    }
 
    /* Prompt the user for a file name and create it */
 
    SFPutFile(dlgPos, (StringPtr)"\pMovie file to create:", (StringPtr)name, nil, &sfr);
    if (!sfr.good)
        return;
    BlockMove(sfr.fName, name, sfr.fName[0] + 1);
    GetGWorld(&saveWorld, &saveGD);
 
 
 
    width = gRect.right - gRect.left;
    height = gRect.bottom - gRect.top;
    if (gOversample)
    {
        width /= 2;
        height /= 2;
    }
    SetRect(&rect, 80, 80, width + 80, height + 80);
    if ((gDstWindow = (CWindowPtr)NewCWindow(nil, &rect, sfr.fName, true, zoomDocProc, (WindowPtr) - 1, true, 0)) == nil)
    {
        Error("NewCWindow Failed", 0);
        goto done;
    }
    BringToFront((WindowPtr)gDstWindow);
    HiliteWindow((WindowPtr)gDstWindow, true);
 
    imageDescriptionH = (ImageDescription * *)NewHandle(sizeof(ImageDescription));/* handle for image descriptor */
    if (imageDescriptionH == nil)
    {
        Error("Out of Memory", MemError());
        goto done;
    }
 
    ClearMoviesStickyError();                   /* Clear any old errors */
    result = FSMakeFSSpec(sfr.vRefNum, 0, (unsigned char*)sfr.fName, &mySpec);
    if (result == fnfErr)
        result = 0;
    CreateMovieFile(&mySpec, 'TVOD', 0, createMovieFileDeleteCurFile, &resRefNum, &gMovie);
 
    gTrack = NewMovieTrack(gMovie, (long)width << 16, (long)height << 16, 0);
    gMedia = NewTrackMedia(gTrack, VideoMediaType, gFrameRate, nil, (OSType)nil);
    BeginMediaEdits(gMedia);                    /* We do this since we are adding samples to the media */
    GetMaxCompressionSize(gAltWorld->portPixMap, &gAltWorld->portRect, gCodecDepth, gCodecQuality, gCodecType, gCodecID, &maxCompressedFrameSize);
 
    compressedFrameBitsH = NewHandle(maxCompressedFrameSize);
    if (compressedFrameBitsH == nil)
    {
        EndMediaEdits(gMedia);
        Error("Out of Memory", MemError());
        goto bail;
    }
    GetGWorld(&saveWorld, &saveGD);
    SetGWorld((CGrafPtr)gDstWorld, nil);
    PaintRect(&gDstWorld->portRect);
 
    if ((result = CompressSequenceBegin(&seq, gDstWorld->portPixMap, nil, &gDstWorld->portRect, nil, gCodecDepth, gCodecType, gCodecID, gCodecQuality, gCodecTemporalQuality, gKeyFrameRate, nil, codecFlagUpdatePreviousComp, imageDescriptionH)) != 0)
    {
        Error("CompressSequenceBegin Failed", result);
        goto bail2;
    }
    SetGWorld(saveWorld, saveGD);
    while (WaitNextEvent(everyEvent, &myEvent, 0, nil) != 0)
    {
        if (HandleEvents(&myEvent))
        {
            CDSequenceEnd(seq);
            EndMediaEdits(gMedia);
            return;
        }
    }
    SetRect(&dstRect, 0, 0, gRect.right / 2, gRect.bottom / 2);
    for (gFrameNumber = 0; gFrameNumber <= gNumberSteps; gFrameNumber++)
    {
        SetGWorld(saveWorld, saveGD);
        if (WaitNextEvent(everyEvent, &myEvent, 0, nil) != 0)
        {
            if (HandleEvents(&myEvent))
            {
                break;
            }
        }
        SetGWorld((CGrafPtr)gDstWorld, nil);
        PaintRect(&gDstWorld->portRect);
 
        if (gDstWorld && gWorld && gAltWorld)
            DoStage(gFrameNumber, gNumberSteps, gBackwards);
 
        SetGWorld((CGrafPtr)gDstWindow, nil);
        InvalRect(&gDstWindow->portRect);
        DoHLock(compressedFrameBitsH);
        data = StripAddress(*compressedFrameBitsH);
        if (gOversample)
        {
            SetGWorld(gBufferWorld, nil);
            CopyBits((BitMap *) * gDstWorld->portPixMap, (BitMap *) * gBufferWorld->portPixMap, &gDstWorld->portRect, &dstRect, ditherCopy, nil);
 
            result = CompressSequenceFrame(seq, gBufferWorld->portPixMap, &dstRect, codecFlagUpdatePreviousComp, data, &compressedFrameSize, nil, nil);
        }
        else
        {
            SetGWorld((CGrafPtr)gDstWorld, nil);
            result = CompressSequenceFrame(seq, gDstWorld->portPixMap, &gDstWorld->portRect, codecFlagUpdatePreviousComp, data, &compressedFrameSize, nil, nil);
        }
        if (result)
        {
            Error("Compress Sequence Frame Failed", result);
            break;
        }
        DoHUnlock(compressedFrameBitsH);
        result = AddMediaSample(gMedia, compressedFrameBitsH, 0L, compressedFrameSize, (TimeValue)1, (SampleDescriptionHandle)imageDescriptionH, 1L, 0, nil);
        if (result)
        {
            Error("AddMediaSample Failed", result);
            break;
        }
    }
bail2:CDSequenceEnd(seq);
bail:EndMediaEdits(gMedia);                     /* We're done adding samples */
    timeVal = GetMediaDuration(gMedia);
    result = InsertMediaIntoTrack(gTrack, 0L, 0L, timeVal, 1L << 16);
    if (result)
    {
        Error("InsertMediaIntoTrack Failed", result);
    }
    result = AddMovieResource(gMovie, resRefNum, nil, nil);
    if (result)
    {
        Error("AddMovieResource Failed", result);
    }
    CloseMovieFile(resRefNum);
 
done:SetGWorld(saveWorld, saveGD);
    if (imageDescriptionH)
        DoDisposHandle((Handle)imageDescriptionH);
    if (compressedFrameBitsH)
        DoDisposHandle((Handle)compressedFrameBitsH);
    if (gMovie)
        DisposeMovie(gMovie);
    if (gDstWindow)
    {
        CloseWindow((WindowPtr)gDstWindow);
        gDstWindow = nil;
    }
    SetGWorld(saveWorld, saveGD);
}
 
 
 
/*********************************************
  Stubs
********************************************/
 
void DoCopy(void)
{
 
}
 
 
void DoCut(void)
{
}
 
 
void DoPaste(void)
{
 
}
 
 
void DoClear(void)
{
 
 
}
 
 
void DoUndo(void)
{
 
 
}
 
 
 
/*********************************************
  Process menu command.
********************************************/
 
short DoCommand(long mResult)
{
    short theMenu,
     theItem;
    Str255 daName;
    GDHandle saveGD;
    CGrafPtr savePort;
    OSErr res = 0;
 
#define HIshort(aLong)      (((aLong) >> 16) & 0xFFFF)
#define LOshort(aLong)      ((aLong) & 0xFFFF)
 
    theItem = LOshort(mResult);
    theMenu = HIshort(mResult);                 /* This is the resource ID */
 
 
    switch (theMenu)
    {
        case APPLE_MENU_ID:
            if (theItem == 1)
            {
                ShowAboutBox();
            }
            else
            {
                GetItem(gMenus[0], theItem, daName);
                GetGWorld(&savePort, &saveGD);
                (void)OpenDeskAcc(daName);
                SetGWorld(savePort, saveGD);
            }
            break;
 
        case FILE_MENU_ID:
            {
 
                switch (theItem)
                {
                    case FILE_M_OPEN:
                        DoOpen(nil);
                        FixMenus();
                        break;
                    case FILE_M_CLOSE:
                        DoClose(gActiveWindow);
                        FixMenus();
                        res = 1;
                        break;
                    case FILE_M_SAVE:
                        FixMenus();
                        break;
                    case FILE_M_QUIT:
                        {
                            Boolean abortion = false;
                            while (gActiveWindow)
                            {
                                if (DoClose(gActiveWindow) < 0)
                                {
                                    abortion = true;
                                    break;
                                }
                            }
                            if (!abortion)
                                gExitFlag = true;/* Request exit */
                            res = 1;
                            break;
                        }
                }
            }
            break;
        case EDIT_MENU_ID:
            if (!SystemEdit(theItem - 1))
            {
                switch (theItem)
                {
                    case EDIT_M_UNDO:
                        DoUndo();
                        break;
                    case EDIT_M_CUT:
                        DoCut();
                        break;
                    case EDIT_M_COPY:
                        DoCopy();
                        break;
                    case EDIT_M_PASTE:
                        DoPaste();
                        break;
                    case EDIT_M_CLEAR:
                        DoClear();
                        break;
                }
            }
            FixMenus();
            break;
 
        case MOVIE_MENU_ID:
 
            switch (theItem)
            {
                case MOVIE_M_COMPRESS:
                    SetCompression();
                    break;
                case MOVIE_M_STAGES:
                    DoClose((WindowPtr)gDstWindow);
                    SetStages();
                    break;
                case MOVIE_M_OVERSAMPLE:
                    gOversample =!gOversample;
                    CheckItem(gMenus[MOVIE_MENU], theItem, gOversample);
                    break;
                case MOVIE_M_BACKWARDS:
                    DoClose((WindowPtr)gDstWindow);
                    gBackwards =!gBackwards;
                    CheckItem(gMenus[MOVIE_MENU], theItem, gBackwards);
                    break;
                case MOVIE_M_PREVIEW:
                    DoPreview();
                    break;
                case MOVIE_M_MOVIE:
                    DoMovie();
                    break;
            }
            break;
 
        default:
            break;
 
    }                                           /*endsw theMenu*/
 
    HiliteMenu(0);
    return (res);
}
 
 
 
/********************************************
  Process events.
********************************************/
 
Boolean HandleEvents(EventRecord* myEvent)
{
    Rect dragRect;
    WindowPtr whichWindow;
    short res = 0;
    GWorldPtr saveWorld;
    GDHandle saveGD;
 
    GetGWorld(&saveWorld, &saveGD);
 
    switch (myEvent->what)
    {
        case mouseDown:
            switch ((short)FindWindow(myEvent->where, &whichWindow))
            {
                case inSysWindow:
                    SystemClick(myEvent, whichWindow);
                    break;
 
                case inMenuBar:
                    res = DoCommand(MenuSelect(myEvent->where));
                    break;
 
                case inDrag:
                    SetPort((GrafPtr)whichWindow);
                    SetRect(&dragRect, 4, 20 + 4, qd.screenBits.bounds.right - 4, qd.screenBits.bounds.bottom - 4);
                    DragWindow(whichWindow, myEvent->where, &dragRect);
                    break;
 
                case inGrow:
                    break;
 
                case inGoAway:
                    if (TrackGoAway(whichWindow, myEvent->where))
                    {
                        DoClose(whichWindow);
                        res = true;
                    }
                    break;
 
                case inZoomIn:
                    break;
 
                case inZoomOut:
                    break;
 
                case inContent:
 
                    if (whichWindow != FrontWindow())
                    {
                        SelectWindow(whichWindow);
                        gActiveWindow = whichWindow;
                    }
                    FixMenus();
                    break;
 
                default:
                    break;
            }
            break;
 
        case keyDown:
            if (((myEvent->modifiers & cmdKey) != 0))
            {
                res = DoCommand(MenuKey(myEvent->message & charCodeMask));
            }
            break;
 
        case updateEvt:
 
            DoUpdate((CWindowPtr)myEvent->message);
            break;
 
        case activateEvt:
            whichWindow = (WindowPtr)myEvent->message;
            if ((myEvent->modifiers & activeFlag))
            {
                gActiveWindow = whichWindow;
            }
            break;
 
        default:
            break;
 
    }
    SetGWorld(saveWorld, saveGD);
    return (res);
}
 
 
 
/********************************************
  Allocate the image buffers for the processing
********************************************/
 
OSErr AllocateBuffers(void)
{
 
    Rect rect = gRect;
    OSErr result = 0;
    short depth = gDepth > 32 ? (gDepth - 32) : gDepth;
    CTabHandle clut = nil;
 
    OffsetRect(&rect, -rect.left, -rect.top);
 
    if (gDepth > 32)
        clut = GetCTable(gDepth);
 
    if (gDstWorld)
    {
        DisposeGWorld(gDstWorld);
        gDstWorld = nil;
    }
    if (gBufferWorld)
    {
        DisposeGWorld(gBufferWorld);
        gBufferWorld = nil;
    }
    if ((result = NewGWorld(&gWorld, depth, &rect, clut, nil, 0)) != 0)
    {
        if ((result = NewGWorld(&gWorld, depth, &rect, clut, nil, useTempMem)) != 0)
        {
            Error("NewGWorld Failed", result);
            goto done;
        }
    }
    if ((result = NewGWorld(&gAltWorld, depth, &rect, clut, nil, 0)) != 0)
    {
        if ((result = NewGWorld(&gAltWorld, depth, &rect, clut, nil, useTempMem)) != 0)
        {
            Error("NewGWorld Failed", result);
            goto done;
        }
    }
    if ((result = NewGWorld(&gBufferWorld, depth, &rect, clut, nil, 0)) != 0)
    {
        if ((result = NewGWorld(&gBufferWorld, depth, &rect, clut, nil, useTempMem)) != 0)
        {
            Error("NewGWorld Failed", result);
            goto done;
        }
    }
    if ((result = NewGWorld(&gDstWorld, depth, &rect, clut, nil, 0)) != 0)
    {
        if ((result = NewGWorld(&gDstWorld, depth, &rect, clut, nil, useTempMem)) != 0)
        {
            Error("NewGWorld Failed", result);
            goto done;
        }
    }
done:if (result)
    {
        if (gWorld)
            DisposeGWorld(gWorld);
        gWorld = nil;
        if (gAltWorld)
            DisposeGWorld(gAltWorld);
        gAltWorld = nil;
        if (gDstWorld)
            DisposeGWorld(gDstWorld);
        gDstWorld = nil;
        if (gBufferWorld)
            DisposeGWorld(gBufferWorld);
        gBufferWorld = nil;
 
    }
    if (clut)
        DisposeCTable(clut);
    return (result);
}
 
 
 
/********************************************
  Make a source window 
********************************************/
 
CWindowPtr MakeSWindow(Rect* frame,
                       StringPtr name,
                       GWorldPtr buffer)
{
    CWindowPtr wind;
 
    if ((wind = (CWindowPtr)NewCWindow(nil, frame, name, false, zoomDocProc, (WindowPtr) - 1, true, 0)) == nil)
    {
        Error("NewCWindow Failed", 0);
        return (nil);
    }
    ShowWindow((WindowPtr)wind);
    BringToFront((WindowPtr)wind);
    HiliteWindow((WindowPtr)wind, true);
    SetWRefCon((WindowPtr)wind, (long)buffer);
    return (wind);
}
 
 
 
 
/********************************************
  Open a file.
********************************************/
 
OSErr DoOpen(FSSpec* fsp)
{
    long result = noErr;
    Rect zpFrame;
    GWorldPtr saveWorld;
    GDHandle saveGD;
    short oFile = -1;
    StandardFileReply theSFR;
 
 
    GetGWorld(&saveWorld, &saveGD);
    if (fsp == nil)
    {
        SFTypeList types =
        {
            'PICT',  0
        }
        ;
 
        if (gHasNewStdFile)
            StandardGetFile(nil, 1, types, &theSFR);
        else
        {
            SFReply osfr;
            Point pt =
            {
                100,  100
            }
            ;
 
            SFGetFile(pt, (ConstStr255Param)"", nil, 1, types, nil, &osfr);
            theSFR.sfGood = osfr.good;
            theSFR.sfReplacing = osfr.copy;
            theSFR.sfType = osfr.fType;
            if (osfr.good)
                FSMakeFSSpec(osfr.vRefNum, 0L, osfr.fName, &theSFR.sfFile);
        }
        if (!theSFR.sfGood)
        {
            return (1);
        }
    }
    else
    {
        theSFR.sfFile = *fsp;
    }
 
    if (FSpOpenDF(&theSFR.sfFile, fsRdPerm, &oFile))
    {
        result = -1;
        goto done;
    }
 
 
    /************************************************
     *
     *  Get the picture frame, to see how big of a window to make.
     *
    ************************************************/
 
    if (GetPictureFileHeader(oFile, &gOriginalPicFrame, nil))
    {
        result = -1;
        goto done;
    }
 
    if (gSrcWindow == nil)
    {
 
        OffsetRect(&gOriginalPicFrame, -gOriginalPicFrame.left, -gOriginalPicFrame.top);
        if (gOversample)
        {
            gOriginalPicFrame.right *= 2;
            gOriginalPicFrame.bottom *= 2;
        }
        gRect = gOriginalPicFrame;
        zpFrame = gRect;
 
        if ((result = AllocateBuffers()) != 0)
            goto done;
        OffsetRect(&zpFrame, 50, 50);
        gSrcWindow = MakeSWindow(&zpFrame, theSFR.sfFile.name, gWorld);
        SetGWorld((CGrafPtr)gWorld, nil);
        if ((result = DrawPictureFile(oFile, &gWorld->portRect, nil)) != 0)
        {
            Error("DrawPictureFile Failed", result);
            goto done;
        }
    }
    else
    {
 
        zpFrame = gRect;
        OffsetRect(&zpFrame, 70, 70);
        gAltWindow = MakeSWindow(&zpFrame, theSFR.sfFile.name, gAltWorld);
        SetGWorld((CGrafPtr)gAltWorld, nil);
        if ((result = DrawPictureFile(oFile, &gAltWorld->portRect, nil)) != 0)
        {
            Error("DrawPictureFile Failed", result);
            goto done;
        }
    }
done:if (oFile != -1)
        FSClose(oFile);
    SetGWorld(saveWorld, saveGD);
    return (result);
 
}
 
 
/********************************************
  Update a window
********************************************/
 
void DoUpdate(CWindowPtr wind)
 
{
 
    GWorldPtr saveWorld,  gw;
    GDHandle saveGD;
    RGBColor gray =
    {
        0xc000,  0xc000, 0xc000
    }
    ;
    char c[32];
 
    GetGWorld(&saveWorld, &saveGD);
    if (wind == gDstWindow)
    {
        BeginUpdate((WindowPtr)wind);
        SetGWorld((CGrafPtr)wind, nil);
        CopyBits((BitMap *) * gDstWorld->portPixMap, (BitMap *) * wind->portPixMap, &gDstWorld->portRect, &wind->portRect, ditherCopy, nil);
        if (gFrameNumber >= 0)
        {
            MoveTo(20, 20);
            TextSize(12);
            TextFace(bold);
            TextMode(patBic);
            NumToString(gFrameNumber + 1, (StringPtr) & c);
            DrawString((StringPtr) & c);
            DrawString((StringPtr)"\p/");
            NumToString(gNumberSteps + 1, (StringPtr) & c);
            DrawString((StringPtr) & c);
            MoveTo(21, 21);
            TextMode(srcOr);
            NumToString(gFrameNumber + 1, (StringPtr) & c);
            DrawString((StringPtr) & c);
            DrawString((StringPtr)"\p/");
            NumToString(gNumberSteps + 1, (StringPtr) & c);
            DrawString((StringPtr) & c);
        }
        EndUpdate((WindowPtr)wind);
        SetGWorld(saveWorld, saveGD);
        return;
    }
    SetGWorld(wind, nil);
    gw = (GWorldPtr)GetWRefCon((WindowPtr)wind);
    BeginUpdate((WindowPtr)wind);
    CopyBits((BitMap *) * gw->portPixMap, (BitMap *) * wind->portPixMap, &gw->portRect, &wind->portRect, ditherCopy, nil);
    EndUpdate((WindowPtr)wind);
    SetGWorld(saveWorld, saveGD);
}
 
 
 
/********************************************
  The main program
********************************************/
 
void main(void)
{
 
    EventRecord myEvent;
 
    Initialize();
    EnterMovies();
 
 
    if (!gDoCrossFade)
    {
        gDepth = 40;                            // randomdotstereogram needs grayscale buffers
        gCodecType = 'smc ';                        // graphics compressor is good choice
        gCodecDepth = gDepth;                   // prime depth for std compression
        gRequiresAlternate = false;             // only needs one pict to do processing
    }
    else
    {
        gDepth = 32;                            // full resolution for best effect
        gRequiresAlternate = true;              // needs two picts to do processing
    }
    while (!gExitFlag)
    {
        if (WaitNextEvent(everyEvent, &myEvent, 1, nil) != 0)
        {
            HandleEvents(&myEvent);
        }
    }
 
done:ExitMovies();
    ExitToShell();
}