Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MyQuickDrawView.m
////////// |
// |
// File: MyQuickDrawView.m |
// |
// Contains: Implementation file for the MyQuickDrawView class. |
// |
// Written by: Apple Developer Technical Support |
// |
// Copyright: © 2002 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <1> 11/18/02 srk first file |
// |
////////// |
/* |
IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in |
consideration of your agreement to the following terms, and your use, installation, |
modification or redistribution of this Apple software constitutes acceptance of these |
terms. If you do not agree with these terms, please do not use, install, modify or |
redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject to these |
terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in |
this original Apple software (the "Apple Software"), to use, reproduce, modify and |
redistribute the Apple Software, with or without modifications, in source and/or binary |
forms; provided that if you redistribute the Apple Software in its entirety and without |
modifications, you must retain this notice and the following text and disclaimers in all |
such redistributions of the Apple Software. Neither the name, trademarks, service marks |
or logos of Apple Computer, Inc. may be used to endorse or promote products derived from |
the Apple Software without specific prior written permission from Apple. Except as expressly |
stated in this notice, no other rights or licenses, express or implied, are granted by Apple |
herein, including but not limited to any patent rights that may be infringed by your |
derivative works or by other works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, |
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, |
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS |
USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, |
REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND |
WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR |
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#import "MyQuickDrawView.h" |
@implementation MyQuickDrawView |
////////// |
// |
// awakeFromNib |
// |
// Called after all our objects are unarchived and |
// connected but just before the interface is made visible |
// to the user. We will do custom initialization of our |
// objects here. |
// |
////////// |
- (void)awakeFromNib |
{ |
NSString *filePath = nil; |
NSURL *fileURL = nil; |
decompressSeqID = 0; // unique identifier for our draw sequence |
firstDrawRect = TRUE; // true for first call to the view's drawRect method |
movie = NULL; // the QuickTime movie we are using |
srcGWorld = NULL; // GWorld we are drawing into |
movieTime = 0; // set current time value to begining of the Movie |
movieFrameCount = 0; // movie frame count |
movieFrameNumber = 1; // current movie frame number |
imageSize = 0; // how big is image |
backgroundImage = nil; // our background image for drawing |
EraseRect(&movieBox); |
filePath = [[NSBundle mainBundle] pathForResource:@"MovieFile" ofType:@"mov"]; |
if (filePath) |
{ |
movie = [self createQTMovieFromMovieFilePath:filePath]; |
if (movie != NULL) |
{ |
/* we must initialize the movie toolbox before calling |
any of it's functions */ |
EnterMovies(); |
movieFrameCount = [self countMovieFrames]; |
// normalize the movie rect |
[self normalizeMovieRect]; |
srcGWorld = [self makeGWorldForMovie]; |
if (srcGWorld != NULL) |
{ |
/* set the graphics world for displaying the movie */ |
SetMovieGWorld(movie, srcGWorld, GetGWorldDevice(srcGWorld)); |
} |
/* retrieve our movie file from our bundle resource */ |
filePath = [[NSBundle mainBundle] pathForResource:@"background" ofType:@"pct"]; |
fileURL = [NSURL fileURLWithPath:filePath]; |
/* create an NSMovie object from our QuickTime movie */ |
backgroundImage = [[NSImage alloc] initWithContentsOfURL:fileURL]; |
if (backgroundImage) |
{ |
[self drawBackgroundImage]; |
} |
/* draw the first frame */ |
[self drawFrame]; |
} |
} |
NSAssert(filePath != nil, @"movie not found in bundle"); |
NSAssert(fileURL != nil, @"fileURLWithPath failed"); |
NSAssert(backgroundImage != nil, @"initWithContentsOfURL failed"); |
} |
////////// |
// |
// createQTMovieFromMovieFilePath |
// |
// Given a path to a movie file, create a |
// QuickTime movie |
// |
////////// |
-(Movie)createQTMovieFromMovieFilePath:(NSString *)movieFilePath |
{ |
NSURL *movieFileURL = nil; |
NSMovie *theNSMovie = nil; |
Movie qtMovie = NULL; |
NSAssert(movieFilePath, @"nil movie file path"); |
movieFileURL = [NSURL fileURLWithPath:movieFilePath]; |
if (movieFileURL != nil) |
{ |
theNSMovie = [[NSMovie alloc] initWithURL:movieFileURL byReference:NO]; |
if (theNSMovie != nil) |
{ |
qtMovie = [theNSMovie QTMovie]; |
if (qtMovie != NULL) |
{ |
SetMovieActive(qtMovie,true); |
} |
} |
} |
NSAssert(movieFileURL != NULL, @"nil movieFileURL"); |
NSAssert(theNSMovie != NULL, @"nil theNSMovie"); |
NSAssert(qtMovie != NULL, @"null qtmovie"); |
return (qtMovie); |
} |
////////// |
// |
// normalizeMovieRect |
// |
// Set the movie rect to be 0,0 based |
// |
////////// |
-(void)normalizeMovieRect |
{ |
NSAssert(movie != NULL, @"NULL movie in normalizeMovieRect"); |
GetMovieBox(movie, &movieBox); |
OffsetRect(&movieBox, -movieBox.left, -movieBox.top); |
SetMovieBox(movie, &movieBox); |
} |
////////// |
// |
// normalizedMovieRectWidth |
// |
// Return the normalized movie rect width |
// |
////////// |
-(float)normalizedMovieRectWidth |
{ |
return((float)(movieBox.right - movieBox.left)); |
} |
////////// |
// |
// normalizedMovieRectHeight |
// |
// Return the normalized movie rect height |
// |
////////// |
-(float)normalizedMovieRectHeight |
{ |
return((float)(movieBox.bottom - movieBox.top)); |
} |
////////// |
// |
// makeGWorldForMovie |
// |
// Get the bounding rectangle of the Movie the create a 32-bit GWorld |
// with those dimensions. |
// This GWorld will be used for rendering Movie frames into. |
// |
////////// |
-(GWorldPtr) makeGWorldForMovie |
{ |
Rect srcRect; |
GWorldPtr newGWorld = NULL; |
CGrafPtr savedPort; |
GDHandle savedDevice; |
OSErr err = noErr; |
GetGWorld(&savedPort, &savedDevice); |
GetMovieBox(movie,&srcRect); |
err = NewGWorld(&newGWorld, |
k32ARGBPixelFormat, |
&srcRect, |
NULL, |
NULL, |
0); |
if (err == noErr) |
{ |
if (LockPixels(GetGWorldPixMap(newGWorld))) |
{ |
Rect portRect; |
RGBColor theBlackColor = { 0, 0, 0 }; |
RGBColor theWhiteColor = { 65535, 65535, 65535 }; |
SetGWorld(newGWorld, NULL); |
GetPortBounds(newGWorld, &portRect); |
RGBBackColor(&theBlackColor); |
RGBForeColor(&theWhiteColor); |
EraseRect(&portRect); |
UnlockPixels(GetGWorldPixMap(newGWorld)); |
} |
} |
SetGWorld(savedPort, savedDevice); |
NSAssert(newGWorld != NULL, @"NULL gworld"); |
return newGWorld; |
} |
////////// |
// |
// countMovieFrames |
// |
// Count the number of video "frames" in the Movie by stepping through |
// all of the video "interesting times", or in other words, the places where the |
// movie displays a new video sample. The time between these interesting times |
// is not necessarily constant. |
// |
////////// |
-(UInt32)countMovieFrames |
{ |
OSType whichMediaType = VIDEO_TYPE; |
short flags = nextTimeMediaSample + nextTimeEdgeOK; |
TimeValue duration; |
TimeValue theTime = 0; |
UInt32 frameCnt = 0; |
NSAssert(movie != NULL, @"NULL movie in countMovieFrames"); |
while (theTime >= 0) |
{ |
frameCnt++; |
GetMovieNextInterestingTime(movie, |
flags, |
1, |
&whichMediaType, |
theTime, |
0, |
&theTime, |
&duration); |
NSAssert(GetMoviesError() == noErr, @"GetMovieNextInterestingTime error"); |
// after the first interesting time, don't include the time we |
// are currently at. |
flags = nextTimeMediaSample; |
} // while |
return frameCnt; |
} |
////////// |
// |
// drawFrame |
// |
// Task the movie to draw the frame to the GWorld |
// |
////////// |
-(void)drawFrame |
{ |
CGrafPtr savedPort; |
GDHandle savedDevice; |
GetGWorld(&savedPort, &savedDevice); |
SetGWorld(srcGWorld, NULL); |
// *** this does the actual drawing into the GWorld *** |
MoviesTask(movie,0); |
SetGWorld(savedPort, savedDevice); |
} |
////////// |
// |
// nextFrame |
// |
// Get the next frame of the movie, set the movie time for that frame |
// then task the movie which will draw the frame to the GWorld |
// finally draw the frame number on top of the image and inval the window rect |
// |
////////// |
-(void)nextFrame |
{ |
NSAssert(srcGWorld != NULL, @"null gworld"); |
NSAssert(movie != NULL, @"null movie"); |
if (movieFrameNumber >= movieFrameCount) |
{ |
// reset the movie time back to the beginning |
// then do it all over again |
movieTime = 0; |
movieFrameNumber = 1; |
GoToBeginningOfMovie(movie); |
} |
else |
{ |
short flags; |
OSType whichMediaType; |
TimeValue duration; |
// get the next frame of the source movie |
flags = nextTimeMediaSample; |
whichMediaType = VIDEO_TYPE; |
// if this is the first frame, include the frame we are currently on |
if (movieFrameNumber == 1) |
{ |
flags |= nextTimeEdgeOK; |
} |
// skip to the next interesting time and get the duration for that frame |
GetMovieNextInterestingTime(movie, |
flags, |
1, |
&whichMediaType, |
movieTime, |
0, |
&movieTime, |
&duration); |
// set the time for the frame and give time to the movie toolbox |
SetMovieTimeValue(movie,movieTime); |
// You now have pixels you can play with in the GWorld! |
// This sample simply blits the contents of the GWorld back to |
// a window with the frame number drawn on top of the image |
movieFrameNumber++; |
} |
} |
////////// |
// |
// initDecompressSeq |
// |
// setup our decompression sequence for drawing |
// into the gworld |
// |
////////// |
-(ComponentResult)initDecompressSeq:(GWorldPtr)gworld destPort:(CGrafPtr)dstPort |
{ |
ComponentResult err = noErr; |
Rect bounds; |
ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0); |
PixMapHandle hPixMap = NULL; |
NSAssert(imageDesc != NULL, @"null ImageDescriptionHandle"); |
NSAssert(gworld != NULL, @"srcGWorld parameter NULL"); |
NSAssert(dstPort != NULL, @"dstPort parameter NULL"); |
/* Set up getting grabbed data into the Window */ |
hPixMap = GetGWorldPixMap(gworld); |
NSAssert(hPixMap != NULL, @"null PixMapHandle"); |
GetPixBounds(hPixMap,&bounds); |
decompressSeqID = 0; |
// returns an image description for the GWorlds PixMap |
// on entry the imageDesc is NULL, on return it is correctly filled out |
// you are responsible for disposing it |
err = MakeImageDescriptionForPixMap(hPixMap, &imageDesc); |
if (err == noErr) |
{ |
imageSize = (GetPixRowBytes(hPixMap) * (*imageDesc)->height); |
// begin the process of decompressing a sequence of frames - see above notes on this call. |
// destination is specified as the QuickDraw port for our NSView |
err = DecompressSequenceBeginS( &decompressSeqID, |
imageDesc, |
GetPixBaseAddr(hPixMap), |
imageSize, |
dstPort, |
NULL, |
&bounds, |
NULL, |
ditherCopy, |
NULL, |
0, |
codecHighQuality, |
anyCodec); |
} |
NSAssert(err == noErr, @"DecompressSequenceBeginS error"); |
if (imageDesc) |
{ |
DisposeHandle((Handle)imageDesc); |
} |
return (err); |
} |
////////// |
// |
// decompress |
// |
// Use our decompression sequence to decompress into the gworld |
// |
////////// |
-(OSErr)decompress |
{ |
ComponentResult err = noErr; |
CodecFlags ignore; |
err = DecompressSequenceFrameS( decompressSeqID, |
GetPixBaseAddr(GetGWorldPixMap(srcGWorld)), |
imageSize, |
0, |
&ignore, |
NULL); |
NSAssert(err == noErr, @"DecompressSequenceFrameS error"); |
return err; |
} |
////////// |
// |
// endDecompress |
// |
// terminate our decompress |
// |
////////// |
-(OSErr)endDecompress |
{ |
NSAssert(decompressSeqID != NULL, @"Null draw seq"); |
return (CDSequenceEnd(decompressSeqID)); |
} |
////////// |
// |
// freeAllocatedObjects |
// |
////////// |
-(void)freeAllocatedObjects |
{ |
[backgroundImage release]; |
} |
////////// |
// |
// drawRect |
// |
// Overridden by subclasses of NSView to draw the receiver's |
// image within aRect. It's here we decompress our frames |
// to the window for display |
// |
////////// |
-(void)drawRect:(NSRect)rect |
{ |
NSImage *image = nil; |
if (firstDrawRect) |
{ |
[self initDecompressSeq:srcGWorld destPort:[self qdPort]]; |
firstDrawRect = FALSE; |
} |
/* decompress frame to gworld */ |
[self decompress]; |
image = [self gworldToNSImage:srcGWorld]; |
if (image) |
{ |
[image setFlipped:YES]; |
[image drawInRect:rect fromRect:rect operation:NSCompositeCopy fraction:0.4]; |
} |
/* draw the frame counter */ |
[self drawFrameCounter]; |
/* draw background image */ |
[self drawBackgroundImage]; |
} |
////////// |
// |
// gworldToNSImage |
// |
// convert contents of a gworld to an NSImage |
// |
////////// |
-(NSImage *)gworldToNSImage:(GWorldPtr) gWorldPtr |
{ |
PixMapHandle pixMapHandle = NULL; |
Ptr pixBaseAddr = nil; |
NSBitmapImageRep *imageRep = nil; |
NSImage *image = nil; |
NSAssert(gWorldPtr != nil, @"nil gWorldPtr"); |
// Lock the pixels |
pixMapHandle = GetGWorldPixMap(gWorldPtr); |
if (pixMapHandle) |
{ |
Rect portRect; |
unsigned portWidth, portHeight; |
int bitsPerSample, samplesPerPixel; |
BOOL hasAlpha, isPlanar; |
int destRowBytes; |
NSAssert(LockPixels(pixMapHandle) != false, @"LockPixels returns false"); |
GetPortBounds(gWorldPtr, &portRect); |
portWidth = (portRect.right - portRect.left); |
portHeight = (portRect.bottom - portRect.top); |
bitsPerSample = 8; |
samplesPerPixel = 4; |
hasAlpha = YES; |
isPlanar = NO; |
destRowBytes = portWidth * samplesPerPixel; |
imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL |
pixelsWide:portWidth |
pixelsHigh:portHeight |
bitsPerSample:bitsPerSample |
samplesPerPixel:samplesPerPixel |
hasAlpha:hasAlpha |
isPlanar:NO |
colorSpaceName:NSDeviceRGBColorSpace |
bytesPerRow:destRowBytes |
bitsPerPixel:0]; |
if (imageRep) |
{ |
char *theData; |
int pixmapRowBytes; |
int rowByte,rowIndex; |
theData = [imageRep bitmapData]; |
pixBaseAddr = GetPixBaseAddr(pixMapHandle); |
if (pixBaseAddr) |
{ |
pixmapRowBytes = GetPixRowBytes(pixMapHandle); |
for (rowIndex=0; rowIndex< portHeight; rowIndex++) |
{ |
unsigned char *dst = theData + rowIndex * destRowBytes; |
unsigned char *src = pixBaseAddr + rowIndex * pixmapRowBytes; |
unsigned char a,r,g,b; |
for (rowByte = 0; rowByte < portWidth; rowByte++) |
{ |
a = *src++; // get source Alpha component |
r = *src++; // get source Red component |
g = *src++; // get source Green component |
b = *src++; // get source Blue component |
*dst++ = r; // set dest. Alpha component |
*dst++ = g; // set dest. Red component |
*dst++ = b; // set dest. Green component |
*dst++ = a; // set dest. Blue component |
} |
} |
image = [[NSImage alloc]initWithSize:NSMakeSize(portWidth, portHeight)]; |
if (image) |
{ |
[image addRepresentation:imageRep]; |
[imageRep release]; |
} |
} |
} |
} |
NSAssert(pixMapHandle != NULL, @"null pixMapHandle"); |
NSAssert(imageRep != nil, @"nil imageRep"); |
NSAssert(pixBaseAddr != nil, @"nil pixBaseAddr"); |
NSAssert(image != nil, @"nil image"); |
if (pixMapHandle) |
{ |
UnlockPixels(pixMapHandle); |
} |
return image; |
} |
////////// |
// |
// drawFrameCounter |
// |
// draws the current frame count |
// |
////////// |
-(void)drawFrameCounter |
{ |
char frame[32]; |
Str255 theString; |
TextSize(12); |
TextMode(srcCopy); |
MoveTo(0,10); |
sprintf(frame,"Frame #%ld",movieFrameNumber); |
CopyCStringToPascal(frame, theString); |
DrawString(theString); |
} |
////////// |
// |
// drawBackgroundImage |
// |
// draw background image |
// |
////////// |
-(void)drawBackgroundImage |
{ |
NSRect srcRect,dstRect; |
srcRect = NSMakeRect(0, 0, [self normalizedMovieRectWidth], [self normalizedMovieRectHeight]); |
dstRect = NSMakeRect(0, 0, [self normalizedMovieRectWidth], [self normalizedMovieRectHeight]); |
[backgroundImage drawInRect:dstRect fromRect:srcRect operation:NSCompositeSourceOver fraction:0.2]; |
} |
@end |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14