Fixed some memory leaks, and took the address-related properties out of Player.
1 /* This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
2 http://developer.apple.com/samplecode/GeekGameBoard/
3 Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
5 Redistribution and use in source and binary forms, with or without modification, are permitted
6 provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice, this list of conditions
9 and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this list of
11 conditions and the following disclaimer in the documentation and/or other materials provided
12 with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
15 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
17 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
19 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
21 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 #import "QuartzUtils.h"
24 #import <QuartzCore/QuartzCore.h>
28 CGColorRef kBlackColor, kWhiteColor,
29 kTranslucentGrayColor, kTranslucentLightGrayColor,
30 kTranslucentWhiteColor, kAlmostInvisibleWhiteColor,
34 __attribute__((constructor)) // Makes this function run when the app loads
35 static void InitQuartzUtils()
37 kBlackColor = CreateGray(0.0, 1.0);
38 kWhiteColor = CreateGray(1.0, 1.0);
39 kTranslucentGrayColor = CreateGray(0.0, 0.5);
40 kTranslucentLightGrayColor = CreateGray(0.0, 0.25);
41 kTranslucentWhiteColor = CreateGray(1, 0.25);
42 kAlmostInvisibleWhiteColor = CreateGray(1, 0.05);
43 kHighlightColor = CreateRGB(1, 1, 0, 0.5);
48 CGColorRef CreateGray(CGFloat gray, CGFloat alpha)
50 CGColorSpaceRef graySpace = CGColorSpaceCreateDeviceGray();
51 CGFloat components[2] = {gray,alpha};
52 CGColorRef color = CGColorCreate(graySpace, components);
53 CGColorSpaceRelease(graySpace);
57 CGColorRef CreateRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha)
59 CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
60 CGFloat components[4] = {red,green,blue,alpha};
61 CGColorRef color = CGColorCreate(rgbSpace, components);
62 CGColorSpaceRelease(rgbSpace);
68 CGImageRef CreateCGImageFromFile( NSString *path )
71 UIImage *uiImage = [UIImage imageWithContentsOfFile: path];
72 if(!uiImage) NSLog(@"Warning: UIImage imageWithContentsOfFile failed on file %@",path);
73 return CGImageRetain(uiImage.CGImage);
75 CGImageRef image = NULL;
76 CFURLRef url = (CFURLRef) [NSURL fileURLWithPath: path];
77 CGImageSourceRef src = CGImageSourceCreateWithURL(url, NULL);
79 image = CGImageSourceCreateImageAtIndex(src, 0, NULL);
81 if(!image) NSLog(@"Warning: CGImageSourceCreateImageAtIndex failed on file %@ (ptr size=%u)",path,sizeof(void*));
88 CGImageRef GetCGImageNamed( NSString *name )
91 name = name.lastPathComponent;
92 UIImage *uiImage = [UIImage imageNamed: name];
93 NSCAssert1(uiImage,@"Couldn't find bundle image resource '%@'",name);
94 return uiImage.CGImage;
96 // For efficiency, loaded images are cached in a dictionary by name.
97 static NSMutableDictionary *sMap;
99 sMap = [[NSMutableDictionary alloc] init];
101 CGImageRef image = (CGImageRef) [sMap objectForKey: name];
103 // Hasn't been cached yet, so load it:
105 if( [name hasPrefix: @"/"] )
108 NSString *dir = [name stringByDeletingLastPathComponent];
109 name = [name lastPathComponent];
110 NSString *ext = name.pathExtension;
111 name = [name stringByDeletingPathExtension];
112 path = [[NSBundle mainBundle] pathForResource: name ofType: ext inDirectory: dir];
113 NSCAssert3(path,@"Couldn't find bundle image resource '%@' type '%@' in '%@'",name,ext,dir);
115 image = CreateCGImageFromFile(path);
116 NSCAssert1(image,@"Failed to load image from %@",path);
117 [sMap setObject: (id)image forKey: name];
118 CGImageRelease(image);
125 CGColorRef GetCGPatternNamed( NSString *name ) // can be resource name or abs. path
127 // For efficiency, loaded patterns are cached in a dictionary by name.
128 static NSMutableDictionary *sMap;
130 sMap = [[NSMutableDictionary alloc] init];
132 CGColorRef pattern = (CGColorRef) [sMap objectForKey: name];
134 pattern = CreatePatternColor( GetCGImageNamed(name) );
135 [sMap setObject: (id)pattern forKey: name];
136 CGColorRelease(pattern);
142 #if ! TARGET_OS_IPHONE
144 BOOL CanGetCGImageFromPasteboard( NSPasteboard *pb )
146 return [NSImage canInitWithPasteboard: pb]
147 || [[pb types] containsObject: @"PixadexIconPathPboardType"];
149 /*if( [[pb types] containsObject: NSFilesPromisePboardType] ) {
150 NSArray *fileTypes = [pb propertyListForType: NSFilesPromisePboardType];
151 NSLog(@"Got file promise! Types = %@",fileTypes);
152 //FIX: Check file types
153 return NSDragOperationCopy;
157 CGImageRef GetCGImageFromPasteboard( NSPasteboard *pb, id<NSDraggingInfo>dragInfo )
159 CGImageSourceRef src = NULL;
160 NSArray *paths = [pb propertyListForType: NSFilenamesPboardType];
161 if( paths.count==1 ) {
162 // If a file is being dragged, read it:
163 CFURLRef url = (CFURLRef) [NSURL fileURLWithPath: [paths objectAtIndex: 0]];
164 src = CGImageSourceCreateWithURL(url, NULL);
166 } else if( dragInfo && [[pb types] containsObject:NSFilesPromisePboardType] ) {
167 NSString *dropDir = NSTemporaryDirectory();
168 NSArray *filenames = [dragInfo namesOfPromisedFilesDroppedAtDestination: [NSURL fileURLWithPath: dropDir]];
169 NSLog(@"promised files are %@ / %@", dropDir,filenames);
171 } else if( [[pb types] containsObject: @"PixadexIconPathPboardType"] ) {
172 // Candybar 3 (nee Pixadex) doesn't drag out icons in any normal image type.
173 // It does support file-promises, but I couldn't get those to work using the Cocoa APIs.
174 // So instead I'm using its custom type that provides the path(s) to its internal ".pxicon" files.
175 // The icon is really easy to get from one of these: it's just file's custom icon.
176 NSArray *files = [pb propertyListForType: @"PixadexIconPathPboardType"];
177 if( files.count == 1 ) {
178 NSString *path = [files objectAtIndex: 0];
179 NSImage *icon = [[NSWorkspace sharedWorkspace] iconForFile: path];
180 for( NSImageRep *rep in icon.representations ) {
181 if( [rep isKindOfClass: [NSBitmapImageRep class]] ) {
182 [rep retain]; //FIX: This leaks; but if the rep goes away, the CGImage breaks...
183 return [(NSBitmapImageRep*)rep CGImage];
188 // Else look for an image type:
189 NSString *type = [pb availableTypeFromArray: [NSImage imageUnfilteredPasteboardTypes]];
191 NSData *data = [pb dataForType: type];
192 src = CGImageSourceCreateWithData((CFDataRef)data, NULL);
196 CGImageRef image = CGImageSourceCreateImageAtIndex(src, 0, NULL);
205 CGImageRef CreateScaledImage( CGImageRef srcImage, CGFloat scale )
207 int width = CGImageGetWidth(srcImage), height = CGImageGetHeight(srcImage);
210 scale /= MAX(width,height); // interpret scale as target dimensions
211 width = ceil( width * scale);
212 height= ceil( height* scale);
215 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
216 CGContextRef ctx = CGBitmapContextCreate(NULL, width, height, 8, 4*width, space,
217 kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast);
218 CGColorSpaceRelease(space);
219 CGContextSetInterpolationQuality(ctx,kCGInterpolationHigh);
220 CGContextDrawImage(ctx, CGRectMake(0, 0, width, height), srcImage);
221 CGImageRef dstImage = CGBitmapContextCreateImage(ctx);
222 CGContextRelease(ctx);
227 CGImageRef GetScaledImageNamed( NSString *imageName, CGFloat scale )
229 // For efficiency, loaded images are cached in a dictionary by name.
230 static NSMutableDictionary *sMap;
232 sMap = [[NSMutableDictionary alloc] init];
234 NSArray *key = [NSArray arrayWithObjects: imageName, [NSNumber numberWithFloat: scale], nil];
235 CGImageRef image = (CGImageRef) [sMap objectForKey: key];
237 // Hasn't been cached yet, so load it:
238 image = CreateScaledImage(GetCGImageNamed(imageName), scale);
239 [sMap setObject: (id)image forKey: key];
240 CGImageRelease(image);
246 float GetPixelAlpha( CGImageRef image, CGSize imageSize, CGPoint pt )
248 NSCParameterAssert(image);
250 // iPhone uses "flipped" (i.e. normal) coords, so images are wrong-way-up
251 pt.y = imageSize.height - pt.y;
255 if( pt.x<0 || pt.x>=imageSize.width || pt.y<0 || pt.y>=imageSize.height )
258 // sTinyContext is a 1x1 CGBitmapContext whose pixmap stores only alpha.
259 static UInt8 sPixel[1];
260 static CGContextRef sTinyContext;
261 if( ! sTinyContext ) {
262 sTinyContext = CGBitmapContextCreate(sPixel, 1, 1,
263 8, 1, // bpp, rowBytes
266 CGContextSetBlendMode(sTinyContext, kCGBlendModeCopy);
269 // Draw the image into sTinyContext, positioned so the desired point is at
270 // (0,0), then examine the alpha value in the pixmap:
271 CGContextDrawImage(sTinyContext,
272 CGRectMake(-pt.x,-pt.y, imageSize.width,imageSize.height),
274 return sPixel[0] / 255.0;
279 #pragma mark PATTERNS:
282 // callback for CreateImagePattern.
283 static void drawPatternImage (void *info, CGContextRef ctx)
285 CGImageRef image = (CGImageRef) info;
286 CGContextDrawImage(ctx,
287 CGRectMake(0,0, CGImageGetWidth(image),CGImageGetHeight(image)),
291 // callback for CreateImagePattern.
292 static void releasePatternImage( void *info )
294 CGImageRelease( (CGImageRef)info );
298 CGPatternRef CreateImagePattern( CGImageRef image )
300 NSCParameterAssert(image);
301 int width = CGImageGetWidth(image);
302 int height = CGImageGetHeight(image);
303 static const CGPatternCallbacks callbacks = {0, &drawPatternImage, &releasePatternImage};
304 return CGPatternCreate (image,
305 CGRectMake (0, 0, width, height),
306 CGAffineTransformMake (1, 0, 0, 1, 0, 0),
309 kCGPatternTilingConstantSpacing,
315 CGColorRef CreatePatternColor( CGImageRef image )
317 CGPatternRef pattern = CreateImagePattern(image);
318 CGColorSpaceRef space = CGColorSpaceCreatePattern(NULL);
319 CGFloat components[1] = {1.0};
320 CGColorRef color = CGColorCreateWithPattern(space, pattern, components);
321 CGColorSpaceRelease(space);
322 CGPatternRelease(pattern);
331 void AddRoundRect( CGContextRef ctx, CGRect rect, CGFloat radius )
333 radius = MIN(radius, floorf(rect.size.width/2));
334 float x0 = CGRectGetMinX(rect), y0 = CGRectGetMinY(rect),
335 x1 = CGRectGetMaxX(rect), y1 = CGRectGetMaxY(rect);
337 CGContextBeginPath(ctx);
338 CGContextMoveToPoint(ctx,x0+radius,y0);
339 CGContextAddArcToPoint(ctx,x1,y0, x1,y1, radius);
340 CGContextAddArcToPoint(ctx,x1,y1, x0,y1, radius);
341 CGContextAddArcToPoint(ctx,x0,y1, x0,y0, radius);
342 CGContextAddArcToPoint(ctx,x0,y0, x1,y0, radius);
343 CGContextClosePath(ctx);