Skip to content

Instantly share code, notes, and snippets.

@Shilo
Last active December 23, 2015 04:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shilo/6577834 to your computer and use it in GitHub Desktop.
Save Shilo/6577834 to your computer and use it in GitHub Desktop.
An extension for Sparrow that allows alpha handing of texture-based objects. (Sparrow 2.X)
//
// SHAlphaButton.h
// Sparrow
//
// Created by Shilo White on 8/13/11.
// Copyright 2011 Shilocity Productions. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SPButton.h"
@interface SHAlphaButton : SPButton {
float mAllowTouchOnAlpha;
}
@property (nonatomic, assign) float allowTouchOnAlpha;
+ (id)buttonWithUpState:(SPTexture *)upState downState:(SPTexture *)downState;
+ (id)buttonWithUpState:(SPTexture *)upState text:(NSString *)text;
+ (id)buttonWithUpState:(SPTexture *)upState;
@end
//
// SHAlphaButton.m
// Sparrow
//
// Created by Shilo White on 8/13/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "SHAlphaButton.h"
#import "SHAlphaTexture.h"
@implementation SHAlphaButton
+ (id)buttonWithUpState:(SPTexture *)upState downState:(SPTexture *)downState {
return [[self alloc] initWithUpState:upState downState:downState];
}
+ (id)buttonWithUpState:(SPTexture *)upState text:(NSString *)text {
return [[self alloc] initWithUpState:upState text:text];
}
+ (id)buttonWithUpState:(SPTexture *)upState {
return [[self alloc] initWithUpState:upState];
}
- (SPDisplayObject *)hitTestPoint:(SPPoint *)localPoint {
SHAlphaTexture *upState = (SHAlphaTexture *)self.upState;
if (![upState isKindOfClass:[SHAlphaTexture class]] && ![upState isKindOfClass:[SHAlphaSubTexture class]] && ![upState isKindOfClass:[SHGLAlphaTexture class]]) {
return [super hitTestPoint:localPoint];
}
if ((!self.visible || !self.touchable) || ![super hitTestPoint:localPoint])
return nil;
float scale = upState.alphaScale;
NSUInteger index = round(localPoint.x*scale) + (round(localPoint.y*scale) * (upState.alphaWidth*scale));
char *rawDataBytes = (char *)[upState.alphaData bytes];
//return (rawDataBytes[index] == 0) ? nil : self;
return (rawDataBytes[index] == -1) ? self : nil;
}
@end
//
// SHAlphaImage.h
// Sparrow
//
// Created by Shilo White on 3/12/12.
// Copyright (c) 2012 Shilocity Productions. All rights reserved.
//
#import "SPImage.h"
@interface SHAlphaImage : SPImage {
float mAllowTouchOnAlpha;
}
@property (nonatomic, assign) float allowTouchOnAlpha;
+ (SHAlphaImage *)imageWithTexture:(SPTexture*)texture;
+ (SHAlphaImage *)imageWithContentsOfFile:(NSString*)path;
- (float)alphaOfPixelWithX:(float)x y:(float)y;
@end
//
// SHAlphaImage.m
// Sparrow
//
// Created by Shilo White on 3/12/12.
// Copyright (c) 2012 Shilocity Productions. All rights reserved.
//
#import "SHAlphaImage.h"
#import "SHAlphaTexture.h"
@interface SHAlphaTexture ()
- (float)alphaOfPixelWithX:(float)x y:(float)y;
@end
@implementation SHAlphaImage
@synthesize allowTouchOnAlpha = mAllowTouchOnAlpha;
- (id)initWithTexture:(SPTexture*)texture {
if ((self = [super initWithTexture:texture])) {
mAllowTouchOnAlpha = 1.0f;
}
return self;
}
- (id)initWithContentsOfFile:(NSString*)path {
return [self initWithTexture:[SHAlphaTexture textureWithContentsOfFile:path]];
}
- (id)initWithWidth:(float)width height:(float)height {
return [self initWithTexture:[SHAlphaTexture textureWithWidth:width height:height draw:NULL]];
}
+ (SHAlphaImage *)imageWithTexture:(SPTexture*)texture {
return [[self alloc] initWithTexture:texture];
}
+ (SHAlphaImage *)imageWithContentsOfFile:(NSString*)path {
return [[self alloc] initWithContentsOfFile:path];
}
- (SPDisplayObject *)hitTestPoint:(SPPoint *)localPoint {
if (mAllowTouchOnAlpha <= 0) return [super hitTestPoint:localPoint];
SHAlphaTexture *texture = (SHAlphaTexture *)self.texture;
if (![texture isKindOfClass:[SHAlphaTexture class]] && ![texture isKindOfClass:[SHAlphaSubTexture class]] && ![texture isKindOfClass:[SHGLAlphaTexture class]]) {
return [super hitTestPoint:localPoint];
}
if ((!self.visible || !self.touchable) || ![super hitTestPoint:localPoint])
return nil;
//NSUInteger index = round(localPoint.x) + (round(localPoint.y) * upState.alphaWidth);
//char *rawDataBytes = (char *)[upState.alphaData bytes];
//return (rawDataBytes[index] == 0) ? nil : self;
//return (rawDataBytes[index] < 0) ? self : nil;
//return (rawDataBytes[index] == -1) ? self : nil;
return ([texture alphaOfPixelWithX:localPoint.x y:localPoint.y] >= mAllowTouchOnAlpha) ? self : nil;
}
- (float)alphaOfPixelWithX:(float)x y:(float)y {
SHAlphaTexture *texture = (SHAlphaTexture *)self.texture;
if (![texture isKindOfClass:[SHAlphaTexture class]] && ![texture isKindOfClass:[SHAlphaSubTexture class]] && ![texture isKindOfClass:[SHGLAlphaTexture class]]) {
return 0;
} else {
return [texture alphaOfPixelWithX:x y:y];
}
}
@end
//
// SPAlphaTexture.h
// Sparrow
//
// Created by Shilo White on 8/13/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SPTexture.h"
#import "SPSubTexture.h"
#import "SPGLTexture.h"
@interface SHAlphaTexture : SPTexture
@property (nonatomic, strong) NSData *alphaData;
@property (nonatomic, assign) float alphaWidth;
@property (nonatomic, assign) float alphaScale;
+ (id)textureWithContentsOfFile:(NSString*)path;
+ (id)textureWithRegion:(SPRectangle *)region ofTexture:(SPTexture *)texture;
+ (id)textureWithWidth:(float)width height:(float)height draw:(SPTextureDrawingBlock)drawingBlock;
+ (id)emptyTexture;
- (float)alphaOfPixelWithX:(float)x y:(float)y;
@end
@interface SHAlphaSubTexture : SPSubTexture {
NSData *mAlphaData;
float mAlphaWidth;
float mAlphaScale;
}
@property (nonatomic, strong) NSData *alphaData;
@property (nonatomic, assign) float alphaWidth;
@property (nonatomic, assign) float alphaScale;
- (float)alphaOfPixelWithX:(float)x y:(float)y;
@end
@interface SHGLAlphaTexture : SPGLTexture {
NSData *mAlphaData;
float mAlphaWidth;
float mAlphaScale;
}
@property (nonatomic, strong) NSData *alphaData;
@property (nonatomic, assign) float alphaWidth;
@property (nonatomic, assign) float alphaScale;
- (float)alphaOfPixelWithX:(float)x y:(float)y;
@end
//
// SPAlphaTexture.m
// Sparrow
//
// Created by Shilo White on 8/13/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "SHAlphaTexture.h"
#import <CoreGraphics/CoreGraphics.h>
@interface SHAlphaTexture ()
+ (NSData *)alphaDataOfCGImage:(CGImageRef)image;
CGContextRef CreateAlphaBitmapContext(CGImageRef image);
@end
@interface SPTexture ()
+ (NSDictionary *)optionsForPath:(NSString *)path mipmaps:(BOOL)mipmaps pma:(BOOL)pma;
+ (BOOL)isCompressedFile:(NSString *)path;
@end
@implementation SHAlphaTexture
- (id)initWithContentsOfFile:(NSString *)path generateMipmaps:(BOOL)mipmaps
premultipliedAlpha:(BOOL)pma
{
NSString *fullPath = [SPUtils absolutePathToFile:path];
if (!fullPath)
[NSException raise:SP_EXC_FILE_NOT_FOUND format:@"File '%@' not found", path];
UIImage *image = [UIImage imageWithContentsOfFile:fullPath];
SHAlphaTexture *texture = [self initWithContentsOfImage:image generateMipmaps:mipmaps];
NSData *alphaData = [SHAlphaTexture alphaDataOfCGImage:image.CGImage];
texture.alphaScale = [fullPath contentScaleFactor];
texture.alphaData = alphaData;
texture.alphaWidth = texture.width;
return texture;
}
+ (void)loadFromFile:(NSString *)path generateMipmaps:(BOOL)mipmaps premultipliedAlpha:(BOOL)pma
onComplete:(SPTextureLoadingBlock)callback;
{
NSString *fullPath = [SPUtils absolutePathToFile:path];
float actualScaleFactor = [fullPath contentScaleFactor];
if ([self isCompressedFile:path])
[NSException raise:SP_EXC_INVALID_OPERATION
format:@"Async loading of gzip-compressed files is not supported"];
if (!fullPath)
[NSException raise:SP_EXC_FILE_NOT_FOUND format:@"File '%@' not found", path];
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:fullPath]] queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *outError)
{
SHAlphaTexture *texture = nil;
if (!outError) {
UIImage *image = [UIImage imageWithData:data scale:actualScaleFactor];
texture = [[SHAlphaTexture alloc] initWithContentsOfImage:image generateMipmaps:mipmaps];
NSData *alphaData = [SHAlphaTexture alphaDataOfCGImage:image.CGImage];
texture.alphaScale = [fullPath contentScaleFactor];
texture.alphaData = alphaData;
texture.alphaWidth = texture.width;
}
callback(texture, outError);
}];
}
- (id)initWithContentsOfImage:(UIImage *)image generateMipmaps:(BOOL)mipmaps
{
NSData *alphaData = [SHAlphaTexture alphaDataOfCGImage:image.CGImage];
SHAlphaTexture *texture = [self initWithWidth:image.size.width height:image.size.height generateMipmaps:mipmaps
scale:image.scale draw:^(CGContextRef context)
{
[image drawAtPoint:CGPointMake(0, 0)];
}];
texture.alphaScale = image.scale;
texture.alphaData = alphaData;
texture.alphaWidth = image.size.width;
return texture;
}
- (id)initWithWidth:(float)width height:(float)height generateMipmaps:(BOOL)mipmaps
scale:(float)scale draw:(SPTextureDrawingBlock)drawingBlock
{
// only textures with sidelengths that are powers of 2 support all OpenGL ES features.
int legalWidth = [SPUtils nextPowerOfTwo:width * scale];
int legalHeight = [SPUtils nextPowerOfTwo:height * scale];
CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
BOOL premultipliedAlpha = YES;
int bytesPerPixel = 4;
void *imageData = calloc(legalWidth * legalHeight * bytesPerPixel, 1);
CGContextRef context = CGBitmapContextCreate(imageData, legalWidth, legalHeight, 8,
bytesPerPixel * legalWidth, cgColorSpace,
bitmapInfo);
CGColorSpaceRelease(cgColorSpace);
// UIKit referential is upside down - we flip it and apply the scale factor
CGContextTranslateCTM(context, 0.0f, legalHeight);
CGContextScaleCTM(context, scale, -scale);
if (drawingBlock)
{
UIGraphicsPushContext(context);
drawingBlock(context);
UIGraphicsPopContext();
}
SHGLAlphaTexture *glTexture = [[SHGLAlphaTexture alloc] initWithData:imageData
width:legalWidth
height:legalHeight
generateMipmaps:mipmaps
scale:scale
premultipliedAlpha:premultipliedAlpha];
CGContextRelease(context);
free(imageData);
SPRectangle *region = [SPRectangle rectangleWithX:0 y:0 width:width height:height];
return [[SHAlphaTexture alloc] initWithRegion:region ofTexture:glTexture];
}
- (id)initWithRegion:(SPRectangle*)region frame:(SPRectangle *)frame ofTexture:(SHAlphaTexture*)texture
{
if (frame || region.x != 0.0f || region.width != texture.width
|| region.y != 0.0f || region.height != texture.height)
{
return (SHAlphaTexture *)[[SHAlphaSubTexture alloc] initWithRegion:region frame:frame ofTexture:texture];
}
else
{
return texture;
}
}
+ (id)emptyTexture {
return [[SHGLAlphaTexture alloc] init];
}
+ (id)textureWithContentsOfFile:(NSString *)path {
return [[SHAlphaTexture alloc] initWithContentsOfFile:path];
}
+ (id)textureWithRegion:(SPRectangle *)region ofTexture:(SPTexture *)texture {
return [[SHAlphaTexture alloc] initWithRegion:region ofTexture:texture];
}
+ (id)textureWithWidth:(float)width height:(float)height draw:(SPTextureDrawingBlock)drawingBlock {
return [[SHAlphaTexture alloc] initWithWidth:width height:height draw:drawingBlock];
}
+ (NSData *)alphaDataOfCGImage:(CGImageRef)image {
CGContextRef context = CreateAlphaBitmapContext(image);
if (context == NULL)
return nil;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
CGRect rect = CGRectMake(0, 0, width, height);
CGContextDrawImage(context, rect, image);
void *data = CGBitmapContextGetData(context);
CGContextRelease(context);
if (!data)
return nil;
size_t dataSize = width * height;
return [NSData dataWithBytes:data length:dataSize];
}
CGContextRef CreateAlphaBitmapContext(CGImageRef image) {
CGContextRef context = NULL;
void *bitmapData;
int bitmapByteCount;
size_t pixelsWide = CGImageGetWidth(image);
size_t pixelsHigh = CGImageGetHeight(image);
bitmapByteCount = pixelsWide * pixelsHigh;
bitmapData = malloc(bitmapByteCount);
if (bitmapData == NULL)
return nil;
context = CGBitmapContextCreate(bitmapData, pixelsWide, pixelsHigh, 8, pixelsWide, NULL, (CGBitmapInfo)kCGImageAlphaOnly);
if (context == NULL) {
free(bitmapData);
fprintf(stderr, "Context not created!");
}
return context;
}
- (float)alphaOfPixelWithX:(float)x y:(float)y { return 0.0f; }
- (void)setAlphaData:(NSData *)alphaData { return; }
- (NSData *)alphaData { return nil; }
- (void)setAlphaWidth:(float)alphaWidth { return; }
- (float)alphaWidth { return 0; }
@end
@implementation SHAlphaSubTexture
@synthesize alphaData = mAlphaData;
@synthesize alphaWidth = mAlphaWidth;
@synthesize alphaScale = mAlphaScale;
- (float)alphaOfPixelWithX:(float)x y:(float)y {
x = floorf(x);
y = floorf(y);
if (x < 0 || x >= self.width || y < 0 || y >= self.height) return 0;
NSUInteger index = x + (y * self.alphaWidth);
char *rawDataBytes = (char *)[self.alphaData bytes];
UInt8 alpha = rawDataBytes[index] & 0x000000ff;
return ((float)alpha/255.0f);
}
@end
@implementation SHGLAlphaTexture
@synthesize alphaData = mAlphaData;
@synthesize alphaWidth = mAlphaWidth;
@synthesize alphaScale = mAlphaScale;
- (float)alphaOfPixelWithX:(float)x y:(float)y {
x = floorf(x);
y = floorf(y);
if (x < 0 || x >= self.width || y < 0 || y >= self.height) return 0;
NSUInteger index = x + (y * self.alphaWidth);
char *rawDataBytes = (char *)[self.alphaData bytes];
UInt8 alpha = rawDataBytes[index] & 0x000000ff;
return ((float)alpha/255.0f);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment