home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-31 | 24.7 KB | 1,014 lines |
-
- #include <objc/NXBundle.h>
- #include <dpsclient/psops.h>
- #include "wraps.h"
-
- #import "MovieView.h"
-
- /*
- * Added xanim support
- * (c) 1995 Andreas Windemuth
- */
-
- #define VERBOSE 0
-
- #define XANIM 1
- #if XANIM
- #import "Animation.h"
- #endif
-
- /*
- * Movie 2.51 - 5/7/92 pjf
- *
- * Differences between 2.5 and 2.51:
- * - the save: method actually has a prayer of working when the
- * user saves on top of an existing movie and the old copy can't be renamed.
- *
- * Differences between 2.0 and 2.5:
- * - buttons to control cache depth
- *
- * - turn off multiframe .tiffs by default (define BC_VERSION_1 if you
- * have a .tiff movie and are too lazy to use tiffutil to turn
- * it into an .anim directory)
- *
- * - now able to save movie (currently-selected depth)
- *
- */
-
- #define maxFrames 1024
-
- @implementation MovieView
-
- //
- - initFrame:(const NXRect *) frameRect
- {
- const char *x;
- [(self = [super initFrame:frameRect]) allocateGState];
- state = STOPPED;
- mode = LOOP;
- maxSize.width = maxSize.height = -1.0;
- moviePath = NULL;
- movieFrame = NULL;
- frameCount = 0;
- anim = nil;
- pingDuringDisplay=NO;
- x=NXGetDefaultValue("Movie","DefaultDepth");
- if (!x) dmode=D_DEF; /* use default depth */
- else switch(atoi(x)) {
- default:
- case 0: dmode=D_DEF; break;
- case 2: dmode=D_2; break;
- case 8: dmode=D_8; break;
- case 12: dmode=D_12; break;
- case 24: dmode=D_24; break;
- };
- updateControls = NO;
- showFrameNumber = YES;
- noOriginals = YES;
- fromStream = YES;
- frameRate = 15.0;
- loading = NO;
- willClose = NO;
- numFrames = 0;
- return self;
- }
-
- - updateControls
- {
- if (loading) {
- [[fNumSlider setMaxValue:numFrames-1] setEnabled:YES];
- [nFramesText setIntValue:numFrames-1];
- }
- [fNumSlider setIntValue:currentFrameIndex];
- [fNumText setIntValue:currentFrameIndex];
- [fNumSlider setEnabled:YES];
- return self;
- }
-
- - drawSelf:(const NXRect *) rects :(int)count
- {
- NXImage *image;
- NXPoint origin = {0.0,0.0};
-
- if (!movieFrame) return nil;
- image = movieFrame[currentFrameIndex].image;
- if (!image) return self;
- [image composite:NX_SOVER toPoint:&origin];
- if ((!fromStream && loading) || showFrameNumber) {
- NXRect r;
- [self getBounds:&r];
- if (!fromStream && loading)
- PSWtext(r.size.width, r.size.height, "Loading ...", currentFrameIndex);
- else
- PSWframe(r.size.width, r.size.height, currentFrameIndex);
- }
- if (pingDuringDisplay) NXPing();
- if ((frameCount >= (int)frameRate)) {
- if (state != STOPPED) {
- double t=[anim getDoubleRealTime]+[anim getSyncTime];
- double afps=frameCount/(t-oldt);
- [actualFpsText setDoubleValue:afps];
- oldt=t;
- }
- frameCount=0;
- }
- if (updateControls || !anim) [self updateControls];
- return self;
- }
-
-
- //
- - (BOOL)open:sender
- {
- #if XANIM
- const char *const types[] = {
- "tiff", "anim", "mpg", "mpeg", "iff", "gif", "txt", "fli", "dl", "pfx", "rle", "avi", "qt", "mov",
- NULL };
- #else
- const char *const types[] = { "tiff", "anim", "mpg", "mpeg", (const char *) NULL };
- #endif
- id pan = [OpenPanel new];
- const char *const *filenames;
- char filename[FILENAME_MAX];
-
- if (![pan runModalForTypes:types]) return NO;
- if ((filenames = [pan filenames]) == NULL) return NO;
- sprintf(filename,"%s/%s", [pan directory], filenames[0]);
- return [self openFile:filename];
- }
-
- - (BOOL)load:sender
- {
- fromStream = NO;
- noOriginals = NO;
- return [self open:sender];
- }
-
- - makeWindow;
- {
- Window *w=[self window];
-
- [w sizeWindow:maxSize.width:maxSize.height]; /* will recache images */
- [w setMiniwindowIcon:"movieDoc.tiff"];
- [w makeKeyAndOrderFront:self];
- [w display];
- return self;
- }
-
- - makePanel:(char *)filename;
- {
- char ptitle[FILENAME_MAX];
- char *ptr=rindex(filename,'/')+1;
-
- if (ptr == (char *)1) ptr=filename;
- sprintf(ptitle,"Controls for %s",ptr);
- [panel setTitle:ptitle];
- [panel setNextResponder:[self window]];
- [depthButtons selectCellAt:(int)dmode:0];
- [self setFps:frameRate];
- [self updateControls];
- [panel orderFront:self];
- return self;
- }
-
- - setFps:(float)fps;
- {
- frameRate = fps;
- [fpsSlider setFloatValue:fps];
- [fpsText setFloatValue:fps];
- switch(state) {
- case FORWARD:
- case REVERSE: if (anim) {
- double period = 1.0/frameRate;
- [anim free];
- anim = [[Animator alloc] initChronon:period adaptation:0.05
- target:self action:@selector(tick:)
- autoStart:YES eventMask:0];
- break;
- };
- case STOPPED: break;
- };
- return self;
- }
-
- - setNoOriginals;
- {
- int i;
- Window *w=[self window];
-
- if (noOriginals) return self;
- if (movieFrame) for (i=0; i<numFrames; i++) if (movieFrame[i].original) {
- [movieFrame[i].original free];
- movieFrame[i].original = nil;
- }
- noOriginals = TRUE;
- [w setMinSize:&maxSize];
- [w setMaxSize:&maxSize];
- return self;
- }
-
- //
- // Terrible kludge to be able to accept event from both
- // the panel and the window (to close). Why can there
- // be no two parallel sessions? It seems to crash, then ...
- //
-
- - beginModal;
- {
- [NXApp beginModalSession:&panelSession for:panel];
- return self;
- }
-
- #define EVENT 0
-
- - runModal;
- {
- #if EVENT
- NXEvent ev;
-
- if ([NXApp peekNextEvent:[[self window] eventMask] into:&ev]) {
- if (ev.window==[[self window] windowNum]) {
- [NXApp endModalSession:&panelSession];
- [NXApp beginModalSession:&windowSession for:[self window]];
- [NXApp runModalSession:&windowSession];
- [NXApp endModalSession:&windowSession];
- [NXApp beginModalSession:&panelSession for:panel];
- }
- }
- if ([NXApp peekNextEvent:[panel eventMask] into:&ev]) {
- if (ev.window==[panel windowNum]) {
- #endif
- [NXApp runModalSession:&panelSession];
- #if EVENT
- }
- }
- #endif
- return self;
- }
-
- - endModal;
- {
- [NXApp endModalSession:&panelSession];
- return self;
- }
-
-
- - (BOOL)openFile:(char *)filename
- {
- if (VERBOSE) debug("openFile: %s\n", filename);
- [self makePanel:filename];
- [[self window] setTitleAsFilename:filename];
- moviePath = copy(filename);
- numFrames = 0;
- loading = YES;
- [self fwd:self];
- return YES;
- }
-
-
-
-
- - addBitmap:bm copy:(BOOL)copyFlag;
- {
- NXSize sz;
- NXRect r;
- int flen, flag=0;
- double period;
-
- // if (VERBOSE) debug("Add bitmap %d/%d (%d)\n", currentFrameIndex, numFrames, stopFrame);
- [bm getSize:&sz];
- if (sz.width > maxSize.width) maxSize.width=sz.width, flag=1;
- if (sz.height > maxSize.height) maxSize.height=sz.height, flag=1;
- if (flag || !numFrames) [[self window] sizeWindow:maxSize.width:maxSize.height];
- if (!numFrames) [self makeWindow];
- flen = ([bm pixelsWide]*[bm pixelsHigh]*[bm bitsPerPixel])>>3;
- if (numFrames*flen>20000000) [self setNoOriginals];
- if (!movieFrame) {
- currentFrameIndex = 0;
- NX_MALLOC(movieFrame, movieFrameStruct, currentFrameIndex+1);
- } else {
- currentFrameIndex++;
- NX_REALLOC(movieFrame, movieFrameStruct, currentFrameIndex+1);
- }
- if (numFrames<=currentFrameIndex) numFrames = currentFrameIndex+1;
- if (!noOriginals)
- movieFrame[currentFrameIndex].original = copyFlag?[bm copy]:bm;
- else movieFrame[currentFrameIndex].original=nil;
- // printf("Frame # %d, Size: %8.3f %8.3f\n", currentFrameIndex, sz.width, sz.height);
- if (!fromStream || !currentFrameIndex) {
- movieFrame[currentFrameIndex].image=[[NXImage alloc] initSize:&sz];
- [movieFrame[currentFrameIndex].image setUnique:YES]; /* make caches disjoint */
- [movieFrame[currentFrameIndex].image setBackgroundColor:NX_COLORBLACK];
- } else {
- movieFrame[currentFrameIndex].image=movieFrame[currentFrameIndex-1].image;
- }
- [self getBounds:&r];
- if ([movieFrame[currentFrameIndex].image lockFocus]) {
- [bm drawIn:&r];
- [movieFrame[currentFrameIndex].image unlockFocus];
- } else error("Could not lock focus on image");
- [self display];
- if (noOriginals && !copyFlag) [bm free];
- period = 1.0/frameRate;
- [self runModal];
- while (currentFrameIndex>=stopFrame || state==STOPPED) {
- if (state==STOPPED) stopFrame = currentFrameIndex;
- [self runModal];
- usleep(10000);
- if (willClose) return self;
- }
- frameCount++;
- NXPing();
- return self;
- }
-
- - loadFrames
- {
- char *ptr, *p1, *p2;
- int n, i;
-
- if (VERBOSE) debug("loadFrames: %d %s\n", state, moviePath);
- if (!moviePath) error("Cannot load frames: no path\n");
- stopFrame = 0;
- currentFrameIndex = 0;
-
- /* get the bitmaps */
- ptr = rindex(moviePath,'.');
- if (ptr && !strcmp(ptr, ".anim")) { /* the file is an Icon-style .anim directory */
- p1 = rindex(moviePath,'/');
- p1 = p1?(p1+1):moviePath;
- p2 = stringf("%s", p1);
- p2[ptr-p1] = '\0';
- [self openAnimDirectory: stringf("%s/%s", moviePath, p2)];
- }
- else if (ptr && (!strcmp(ptr,".mpg")||!strcmp(ptr,".mpeg"))) { /* an MPEG file */
- [self openMPEGfile:moviePath];
- }
- else if (ptr && !strcmp(ptr,".tiff")) { /* a slew o' TIFFs in one file */
- List *bitmaps;
-
- bitmaps = [NXBitmapImageRep newListFromFile:moviePath];
- if (!bitmaps) {
- NXRunAlertPanel(NULL,"Couldn't get bitmaps from %s",
- NULL,NULL,NULL, moviePath);
- return self;
- };
- n = [bitmaps count];
- for (i=0; i<n; i++) [self addBitmap:[bitmaps objectAt:i] copy:NO];
- [bitmaps free]; /* does not free elements */
- }
- #if XANIM
- else if ([self openAnimation:moviePath]) {}
- #endif
- else { /* this shouldn't happen */
- [self stop:self];
- NXRunAlertPanel(NULL,"Unknown movie type %s",NULL,NULL,NULL,moviePath);
- return self;
- };
- if (willClose) return self;
- if (fromStream) {
- [self freeFrames];
- movieFrame = NULL;
- [self updateControls];
- if (numFrames>1 && mode == LOOP) [self loadFrames];
- if (willClose) return self;
- if (mode == BOUNCE)
- NXRunAlertPanel(NULL, "Cannot bounce while loading",NULL,NULL,NULL);
- }
- [self endModal];
- [self updateControls];
- loading = NO;
- [self fwd:self];
- return self;
- }
-
-
- - (List *)listAnimDirectory:(char *)filenameRoot
- {
- List *bitmaps = [[List alloc] init];
- int i=0;
-
- while (1) {
- char buf[FILENAME_MAX];
- NXBitmapImageRep *newbitmap;
- sprintf(buf,"%s.%d.tiff",filenameRoot,i++);
- if ((access(buf,R_OK)) == -1) break;
- newbitmap = [[NXBitmapImageRep alloc] initFromFile:buf];
- if (!newbitmap) {
- NXRunAlertPanel(NULL,"Couldn't get bitmap from %s",NULL,NULL,NULL,
- buf);
- [[bitmaps freeObjects] free];
- return nil;
- }
- else
- [bitmaps addObject:newbitmap];
- };
- return bitmaps;
- }
-
- - openAnimDirectory:(char *)rfn;
- {
- int i;
- NXBitmapImageRep *newbitmap;
- char *fn;
-
- for (i=1; TRUE; i++) {
- fn = stringf("%s.%d.tiff", rfn, i);
- if ((access(fn, R_OK)) == -1) break;
- newbitmap = [[NXBitmapImageRep alloc] initFromFile:fn];
- if (!newbitmap) {
- NXRunAlertPanel(NULL,"Couldn't get bitmap from %s",NULL,NULL,NULL, fn);
- continue;
- }
- [self addBitmap:newbitmap copy:NO];
- if (willClose) break;
- }
- return self;
- }
-
- #if XANIM
- - (BOOL)openAnimation:(const char *)filename
- {
- int i;
- NXBitmapImageRep *bm;
- Animation *a;
-
- a = [[Animation alloc] initFrom:filename];
- if (!a) {
- [a free];
- return NO;
- }
- for (i=0; TRUE; i++) {
- bm = [a next];
- if (bm) [self addBitmap:bm copy:YES];
- if ([a isLast] || willClose) break;
- }
- [a getMaxSize:&maxSize];
- return YES;
- }
- #endif
-
- - openMPEGfile:(char *)filename
- {
- int i, n, flen;
- char command[256];
- FILE *fd;
- mpegInfo *pInfo;
- long data;
- BOOL swab;
- NXStream *pStream;
- NXBitmapImageRep *bm;
-
- if (!(fd = fopen(filename, "r"))) error("Could not open %s", filename);
- fread(&data, 4, 1, fd);
- if (data!=0x000001b3 && data!=0xb3010000)
- error("%s does not contain an mpeg stream: %x", filename, data);
- if (data==0xb3010000) swab=YES; else swab=NO;
- if (!(pInfo = calloc(1, sizeof(mpegInfo)))) error("Could not allocate pInfo.");
- // Get horizontal and vertical size of image space
- // as two 12 bit words, respectively
- // then aspect ratio and picture rate
- // as two 4 bit words.
- fread(&data, 4, 1, fd); if (swab) data = NXSwapLong(data);
- pInfo->picture_rate = 0x0F & data;
- data >>= 4;
- pInfo->aspect_ratio = 0x0F & data;
- data >>= 4;
- // In Motorola format, least significant bits come last
- // v_size is actually the second value in the file
- // i.e. h:12,v:12,a:4,p:4
- pInfo->v_size = 0x0FFF & data;
- pInfo->h_size = 0x0FFF & data >> 12;
- maxSize.width = ((pInfo->h_size + 15) / 16) * 16.0;
- maxSize.height = ((pInfo->v_size + 15) / 16) * 16.0;
- // Get bit rate, vbv buffer size, and constrained parameter flag
- fread(&data, 4, 1, fd); if (swab) data = NXSwapLong(data);
- // throw away (non) intra quant matrix flags
- data >>= 2;
- pInfo->const_param_flag = 1 & data;
- data >>= 1;
- pInfo->vbv_buffer_size = 0x03FF & data;
- data >>= 10 + 1; // 1 marker bit
- pInfo->bit_rate = 0x03FFFF & data;
- fclose(fd);
- pInfo->fps = pInfo->picture_rate;
- flen = 3 * (int)maxSize.width * (int)maxSize.height;
-
- // printf("Dimensions: %d %d, buffer size:%d\n", (int)maxSize.width, (int)maxSize.height, flen);
- sprintf(command, "exec %s/mpegDecode %s",
- [[NXBundle mainBundle] directory], filename);
- if (!(fd = popen(command, "r")))
- error("Could not create MPEG process:\n %s", command);
- pStream = NXOpenFile(fileno(fd), O_RDONLY);
-
- // printf("Reading frames:\n");
- if (!numFrames) [self setFps:pInfo->fps];
- bm = [[NXBitmapImageRep alloc] initData:NULL
- pixelsWide:(int)maxSize.width
- pixelsHigh:(int)maxSize.height
- bitsPerSample:8
- samplesPerPixel:3 // (cSpace == RGB_COLOR) ? 3 : 1
- hasAlpha:NO
- isPlanar:NO
- colorSpace:NX_RGBColorSpace
- bytesPerRow:0
- bitsPerPixel:0
- ];
- for (i=0; TRUE; i++) {
- if (4!=NXRead(pStream, &data, 4)) break;
- // printf("Frame # %d.\n", data);
- n = NXRead(pStream, [bm data], flen);
- if (n!=flen) error("Error reading image data (%d/%d bytes read).", n, flen);
- [self addBitmap:bm copy:YES];
- if (willClose) break;
- }
- [bm free];
- if (numFrames<2) {
- NXRunAlertPanel("Read MPEG",
- "Problem reading mpeg stream, no frames found",NULL,NULL,NULL);
- }
- return self;
- }
-
- NXWindowDepth deps[] = {
- NX_DefaultDepth, NX_TwoBitGrayDepth,
- NX_EightBitGrayDepth, NX_TwelveBitRGBDepth,
- NX_TwentyFourBitRGBDepth /*,NX_PurinaCatChow__ChowChowChowDepth*/
- };
-
- // set up Frame data structures and find max frame size
- - allocateFrames:(List *)frames
- {
- int i;
- numFrames=[frames count];
- NX_MALLOC(movieFrame,movieFrameStruct,numFrames);
- for(i=0;i<numFrames;i++) {
- NXImage *nxi;
- NXBitmapImageRep *bm=[frames objectAt:i];
- NXSize sz;
- [bm getSize:&sz];
- movieFrame[i].original=bm;
- nxi=movieFrame[i].image=[[NXImage alloc] initSize:&sz];
- [nxi setUnique:YES]; /* make caches disjoint */
- [nxi setBackgroundColor:NX_COLORBLACK];
- /* keep track of largest frame */
- if (sz.width > maxSize.width) maxSize.width=sz.width;
- if (sz.height > maxSize.height) maxSize.height=sz.height;
- };
- return self;
- }
-
- /*****************************************************************
- *****************************************************************/
- - superviewSizeChanged:(NXSize *)old
- {
- [anim stopEntry];
- [super superviewSizeChanged:old];
- if (noOriginals) {
- if (!fromStream)
- NXRunAlertPanel("Resize","Can't resize, no originals.",NULL,NULL,NULL);
- }
- else if (!loading) {
- [self recache];
- [self renderFrames];
- }
- if (movieFrame) [[self window] display];
- NXPing();
- [anim resetRealTime];
- [anim startEntry];
- return self;
- }
-
- - renderFrames
- {
- int cfi;
- NXRect r;
-
- error("Fix renderFrames!\n");
- [self getBounds:&r];
- cfi = currentFrameIndex;
- for(currentFrameIndex=0; currentFrameIndex<numFrames; currentFrameIndex++) {
- if ([movieFrame[currentFrameIndex].image lockFocus]) {
- [movieFrame[currentFrameIndex].original drawIn:&r];
- [movieFrame[currentFrameIndex].image unlockFocus];
- } else {
- fprintf(stderr,"Barf: couldn't lockFocus on image %d\n",
- (int)movieFrame[currentFrameIndex].image);
- abort();
- }
- [self display];
- NXPing();
- }
- currentFrameIndex = cfi;
- return self;
- }
-
- - recache
- // assume depth & size both changed
- //
- // Appkit bug? Can one render down from 24 bit color to 2 bit gray?
- //
- {
- NXRect r;
- int i;
- [self getBounds:&r];
- [self freeCaches];
- for(i=0; i<numFrames; i++) {
- movieFrame[i].image=[[NXImage alloc] initSize:&r.size];
- [movieFrame[i].image useCacheWithDepth:deps[(int)dmode]];
- };
- return self;
- }
-
- - save:sender
- {
- const char *type = "anim"; // will only save in .anim format.
- SavePanel *sp = [SavePanel new];
- [sp setDelegate:self];
- [sp setRequiredFileType:type];
- if ([sp runModal]) { // OK was hit
- int i;
- char cwd[MAXPATHLEN];
- /* if directory exists, rename it with a wiggle in back. */
- if (access([sp filename],F_OK) == 0) {
- /* I could do this with a couple of calls to system(), but noooo,
- * I had to do it the had way. yeccch. */
- char *buf=malloc(strlen([sp filename]+2));
- sprintf(buf,"%s~",[sp filename]);
- if (!getwd(cwd)) {
- NXRunAlertPanel("FATAL","Couldn't get current directory.",NULL,NULL,NULL);
- abort();
- };
- if (rename([sp filename],buf) == -1) {
- // sledgehammer time.
- struct direct *de;
- DIR *dp;
- chdir([sp filename]);
- dp=opendir(".");
- while(de=readdir(dp)) unlink(de->d_name);
- closedir(dp);
- chdir(cwd);
- unlink([sp filename]);
- };
- };
- mkdir([sp filename],0755);
- chdir([sp filename]);
- for(i=0;i<numFrames;i++) {
- char buf3[MAXPATHLEN];
- char buf2[MAXPATHLEN];
- char *ptr;
- int fd;
- NXStream *s;
- strcpy(buf3,[sp filename]);
- ptr=rindex(buf3,'/')+1;
- *(rindex(ptr,'.'))='\0';
- sprintf(buf2,"./%s.%d.tiff",ptr,i+1);
- fd=open(buf2,O_WRONLY|O_CREAT,0644);
- s=NXOpenFile(fd,NX_WRITEONLY);
- [movieFrame[i].image writeTIFF:s];
- NXClose(s);
- close(fd);
- };
- chdir(cwd);
- };
- return self;
- }
-
- - (BOOL) panelValidateFilenames:sender
- {
- if (!strcmp([sender filename],moviePath)) {
- NXRunAlertPanel("Save","Cannot overwrite original movie",NULL,NULL,NULL);
- return NO;
- };
- return YES;
- }
-
- - freeCaches
- {
- int i;
-
- if (fromStream) [movieFrame[currentFrameIndex].image free];
- else for(i=0;i<numFrames;i++) [movieFrame[i].image free];
- return self;
- }
-
- - freeOriginals
- {
- int i;
- if (!noOriginals) for(i=0;i<numFrames;i++) {
- [movieFrame[i].original free];
- movieFrame[i].original = nil;
- }
- return self;
- }
-
- - freeFrames
- {
- [self freeCaches];
- if (!noOriginals) [self freeOriginals];
- NX_FREE(movieFrame);
- return self;
- }
-
- - free
- {
- cfree(moviePath);
- [self freeGState];
- if (anim) [anim free];
- return [super free];
- }
-
- - copy:sender
- {
- char *buffer;
- NXStream *stream;
- int length, maxLength;
- Pasteboard *pasteboard = [Pasteboard new];
- runState s=state;
-
- [anim stopEntry];
- if (state!=STOPPED) [self stop:self];
- [pasteboard declareTypes:&NXPostScriptPboardType num:1 owner:self];
- stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- [self copyPSCodeInside:&bounds to:stream];
- NXFlush(stream);
- NXGetMemoryBuffer(stream, &buffer, &length, &maxLength);
- [pasteboard writeType:NXPostScriptPboard data:buffer length:length];
- NXCloseMemory(stream, NX_FREEBUFFER);
- switch(s) {
- case STOPPED: break;
- case FORWARD:
- case REVERSE: [anim startEntry]; break;
- };
- return self;
- }
-
- - tick:sender
- {
- int next, end;
-
- // if (VERBOSE) debug("tick: %d %d\n", state, loading);
- if (state==STOPPED) error("Orphaned tick\n");
- if (loading) {
- if (movieFrame) {
- if (stopFrame<=currentFrameIndex) stopFrame++;
- return self;
- }
- if (state!=FORWARD) error("Wrong loading direction: %d\n", state);
- [self beginModal];
- [self loadFrames];
- [self endModal];
- if (willClose) [window performClose:self];
- return self;
- }
- end = (state == FORWARD) ? numFrames-1 : 0;
- switch(mode) {
- case ONCE:
- if (currentFrameIndex == end) {
- [self stop:self];
- return self;
- } else currentFrameIndex += (int)state;
- break;
- case LOOP:
- next = currentFrameIndex + (int)state;
- if (((state == FORWARD)&&(next>end)) ||
- ((state == REVERSE)&&(next<end))) {
- currentFrameIndex = (state < 0) ? numFrames-1 : 0;
- } else currentFrameIndex = next;
- break;
- case BOUNCE:
- next = currentFrameIndex + (int)state;
- if (((state == FORWARD)&&(next>end)) ||
- ((state == REVERSE)&&(next<end))) {
- if (state == FORWARD) [self selectStateButton:REV];
- if (state == REVERSE) [self selectStateButton:FWD];
- state *= -1;
- currentFrameIndex += (int)state;
- } else currentFrameIndex = next;
- break;
- };
- frameCount++;
- [self display];
- return self;
- }
-
- /*****************************************************************
- *****************************************************************/
-
- - fwd:sender
- {
- if (VERBOSE) debug("fwd: \n");
- if (state != STOPPED) [self stop:self];
- state = FORWARD;
- [self move:sender];
- return self;
- }
-
- - rev:sender
- {
- if (VERBOSE) debug("rev: \n");
- if (loading) {
- NXRunAlertPanel(NULL,"Cannot reverse while loading.",NULL,NULL,NULL);
- return self;
- }
- if (state != STOPPED) [self stop:self];
- state = REVERSE;
- [self move:sender];
- return self;
- }
-
- - move:sender
- {
- double period = 1.0/frameRate;
-
- if (VERBOSE) debug("move: %d\n", state);
- anim = [[Animator alloc]
- initChronon:period adaptation:0.05 /*?*/
- target:self action:@selector(tick:)
- autoStart:YES eventMask:0
- ];
- if (state == FORWARD) [self selectStateButton:FWD];
- if (state == REVERSE) [self selectStateButton:REV];
- [fNumText setStringValue:""];
- [fNumSlider setEnabled:NO];
- oldt=[anim getSyncTime];
- frameCount = 0;
- return self;
- }
-
- - stop:sender
- {
- if (loading && state==STOPPED) { /* Quit this movie even while loading */
- willClose = YES; /* Has to propagate through recursive loadFrames calls */
- return self;
- }
- switch(state) {
- case FORWARD:
- case REVERSE: if (anim) [anim free]; anim=nil;
- case STOPPED: break;
- }
- state = STOPPED;
- [self selectStateButton:STOP];
- [self updateControls];
- // [self display];
- return self;
- }
-
- - fwdStep:sender
- {
- [self step:(int) FORWARD];
- return self;
- }
-
- - revStep:sender
- {
- if (loading) {
- NXRunAlertPanel(NULL, "Cannot reverse while loading.",NULL,NULL,NULL);
- return self;
- }
- [self step:(int) REVERSE];
- return self;
- }
-
- - step:(int) direction
- {
- if (VERBOSE) debug("Step: %d %d %d %d\n", direction,
- currentFrameIndex, stopFrame, numFrames);
- if (state != STOPPED) [self stop:self];
- if (loading) {
- stopFrame += direction;
- state = direction;
- } else {
- if (((currentFrameIndex = currentFrameIndex + direction) % numFrames) < 0)
- currentFrameIndex = numFrames + currentFrameIndex;
- }
- [self selectStateButton:STOP];
- return [self display];
- }
-
- - reSize:(NXSize *)s
- {
- if (noOriginals)
- NXRunAlertPanel("Resize","Resize disabled for lack of memory.",NULL,NULL,NULL);
- else [[self window] sizeWindow:s->width :s->height];
- return self;
- }
-
- - expand2x:sender
- {
- NXRect r;
- [self getBounds:&r];
- r.size.width *= 2.0;
- r.size.height *= 2.0;
- [self reSize:&r.size];
- return self;
- }
-
- - reduce50pct:sender
- {
- NXRect r;
- [self getBounds:&r];
- r.size.width *= 0.5;
- r.size.height *= 0.5;
- [self reSize:&r.size];
- return self;
- }
-
- - restore:sender
- {
- [self reSize:&maxSize];
- return self;
- }
-
-
- - modeButtonsChanged:sender
- {
- mode = (runMode)[sender selectedRow];
- return self;
- }
-
- - fNumSliderChanged:sender
- {
- stopFrame = [sender intValue];
- if (loading || currentFrameIndex == stopFrame) return self;
- currentFrameIndex = stopFrame;
- [self stop:self];
- [self display];
- return self;
- }
-
- - fpsSliderChanged:sender
- {
- [self setFps:[sender floatValue]];
- return self;
- }
-
- - pingButtonChanged:sender
- {
- switch([sender selectedRow]) {
- case 0: pingDuringDisplay=NO; break;
- case 1: pingDuringDisplay=YES; break;
- };
- return self;
- }
-
- - selectStateButton:(runState)b
- {
- [stateButtons selectCellAt:0:((int)b)];
- return self;
- }
-
- - depthButtonsChanged:sender
- {
- if (noOriginals) {
- NXRunAlertPanel("Depth","Can't change depth, no originals.",NULL,NULL,NULL);
- return self;
- }
- dmode=(depthMode)[sender selectedRow];
- [anim stopEntry];
- [self recache];
- [self renderFrames];
- [self display];
- [anim resetRealTime];
- [anim startEntry];
- return self;
- }
-
- - updateCheckBoxChanged:sender
- {
- updateControls = !updateControls;
- return self;
- }
-
- - frameCheckBoxChanged:sender
- {
- showFrameNumber = !showFrameNumber;
- return self;
- }
-
-
- // Window's delegate methods
-
- - windowWillClose:sender
- {
- [panel close];
- [self free];
- return self;
- }
-
- -windowDidMiniaturize:sender
- {
- [panel orderOut:sender];
- [anim stopEntry];
- return self;
- }
-
- -windowDidDeminiaturize:sender
- {
- [panel orderFront:sender];
- [anim resetRealTime];
- [anim startEntry];
- return self;
- }
- @end
-