mirror of https://github.com/LIJI32/SameBoy.git
237 lines
7.8 KiB
Objective-C
237 lines
7.8 KiB
Objective-C
#import "GBTheme.h"
|
|
#import "GBVerticalLayout.h"
|
|
#import "GBHorizontalLayout.h"
|
|
#import "GBBackgroundView.h"
|
|
|
|
@interface GBLazyObject : NSProxy
|
|
@end
|
|
|
|
@implementation GBLazyObject
|
|
{
|
|
id _target;
|
|
id (^_constructor)(void);
|
|
}
|
|
|
|
|
|
- (instancetype)initWithConstructor:(id (^)(void))constructor
|
|
{
|
|
_constructor = constructor;
|
|
return self;
|
|
}
|
|
|
|
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
|
|
{
|
|
if (GB_likely(!_target)) {
|
|
_target = _constructor();
|
|
_constructor = nil;
|
|
}
|
|
return [_target methodSignatureForSelector:sel];
|
|
}
|
|
|
|
- (void)forwardInvocation:(NSInvocation *)invocation
|
|
{
|
|
if (GB_likely(!_target)) {
|
|
_target = _constructor();
|
|
_constructor = nil;
|
|
}
|
|
invocation.target = _target;
|
|
[invocation invoke];
|
|
}
|
|
|
|
- (instancetype)self
|
|
{
|
|
if (GB_likely(!_target)) {
|
|
_target = _constructor();
|
|
_constructor = nil;
|
|
}
|
|
return _target;
|
|
}
|
|
|
|
@end
|
|
|
|
#define MakeColor(r, g, b) [UIColor colorWithRed:(r) / 255.0 green:(g) / 255.0 blue:(b) / 255.0 alpha:1.0]
|
|
|
|
__attribute__((objc_direct_members))
|
|
@implementation GBTheme
|
|
{
|
|
NSDictionary<NSString *, UIImage *> *_imageOverrides;
|
|
UIImage *_horizontalPreview;
|
|
UIImage *_verticalPreview;
|
|
}
|
|
|
|
|
|
// Assumes the image has a purple hue
|
|
+ (UIImage *)_recolorImage:(UIImage *)image withColor:(UIColor *)color
|
|
{
|
|
double scale = image.scale;
|
|
|
|
image = [UIImage imageWithCGImage:image.CGImage scale:1.0 orientation:UIImageOrientationUp];
|
|
|
|
CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
|
|
CIFilter *filter = [CIFilter filterWithName:@"CIColorMatrix"];
|
|
double r, g, b;
|
|
[color getRed:&r green:&g blue:&b alpha:NULL];
|
|
|
|
[filter setDefaults];
|
|
[filter setValue:ciImage forKey:@"inputImage"];
|
|
|
|
[filter setValue:[CIVector vectorWithX:r * 1.34 Y:1 - r Z:0 W:0] forKey:@"inputRVector"];
|
|
[filter setValue:[CIVector vectorWithX:g * 1.34 Y:1 - g Z:0 W:0] forKey:@"inputGVector"];
|
|
[filter setValue:[CIVector vectorWithX:b * 1.34 Y:1 - b Z:0 W:0] forKey:@"inputBVector"];
|
|
|
|
[filter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"];
|
|
|
|
|
|
CIContext *context = [CIContext context];
|
|
CGImageRef cgImage = [context createCGImage:filter.outputImage fromRect:filter.outputImage.extent];
|
|
image = [UIImage imageWithCGImage:cgImage scale:scale orientation:0];
|
|
CGImageRelease(cgImage);
|
|
|
|
return image;
|
|
}
|
|
|
|
+ (UIImage *)recolorImage:(UIImage *)image withColor:(UIColor *)color
|
|
{
|
|
return (id)[[GBLazyObject alloc] initWithConstructor:^id{
|
|
return [self _recolorImage:image withColor:color];
|
|
}];
|
|
}
|
|
|
|
- (instancetype)initDefaultTheme
|
|
{
|
|
self = [super init];
|
|
|
|
_brandColor = [UIColor colorWithRed:0 / 255.0 green:70 / 255.0 blue:141 / 255.0 alpha:1.0];
|
|
_backgroundGradientTop = [UIColor colorWithRed:192 / 255.0 green:195 / 255.0 blue:199 / 255.0 alpha:1.0];
|
|
_backgroundGradientBottom = [UIColor colorWithRed:174 / 255.0 green:176 / 255.0 blue:180 / 255.0 alpha:1.0];
|
|
|
|
_bezelsGradientTop = [UIColor colorWithWhite:53 / 255.0 alpha:1.0];
|
|
_bezelsGradientBottom = [UIColor colorWithWhite:45 / 255.0 alpha:1.0];
|
|
|
|
_name = @"SameBoy";
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)setupBackgroundWithColor:(uint32_t)color
|
|
{
|
|
uint8_t r = color >> 16;
|
|
uint8_t g = color >> 8;
|
|
uint8_t b = color;
|
|
|
|
_backgroundGradientTop = MakeColor(r, g, b);
|
|
_backgroundGradientBottom = [UIColor colorWithRed:pow(r / 255.0, 1.125) green:pow(g / 255.0, 1.125) blue:pow(b / 255.0, 1.125) alpha:1.0];
|
|
}
|
|
|
|
- (void)setupButtonsWithColor:(UIColor *)color
|
|
{
|
|
_imageOverrides = @{
|
|
@"button": [GBTheme recolorImage:[UIImage imageNamed:@"button"] withColor:color],
|
|
@"buttonPressed": [GBTheme recolorImage:[UIImage imageNamed:@"buttonPressed"] withColor:color],
|
|
|
|
@"dpad": [GBTheme recolorImage:[UIImage imageNamed:@"dpad-tint"] withColor:color],
|
|
@"swipepad": [GBTheme recolorImage:[UIImage imageNamed:@"swipepad-tint"] withColor:color],
|
|
|
|
@"button2": [GBTheme recolorImage:[UIImage imageNamed:@"button2-tint"] withColor:color],
|
|
@"button2Pressed": [GBTheme recolorImage:[UIImage imageNamed:@"button2Pressed-tint"] withColor:color],
|
|
};
|
|
}
|
|
|
|
- (instancetype)initDarkTheme
|
|
{
|
|
self = [super init];
|
|
|
|
[self setupBackgroundWithColor:0x181c23];
|
|
|
|
_brandColor = [UIColor colorWithRed:0 / 255.0 green:70 / 255.0 blue:141 / 255.0 alpha:1.0];
|
|
_bezelsGradientTop = [UIColor colorWithWhite:53 / 255.0 alpha:1.0];
|
|
_bezelsGradientBottom = [UIColor colorWithWhite:45 / 255.0 alpha:1.0];
|
|
|
|
[self setupButtonsWithColor:MakeColor(0x08, 0x0c, 0x12)];
|
|
|
|
_name = @"SameBoy Dark";
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
- (UIColor *)buttonColor
|
|
{
|
|
double r, g, b;
|
|
[_brandColor getRed:&r green:&g blue:&b alpha:NULL];
|
|
if (r == 1.0 && g == 1.0 && b == 1.0) {
|
|
return _backgroundGradientTop;
|
|
}
|
|
return [UIColor colorWithRed:r green:g blue:b alpha:1.0];
|
|
}
|
|
|
|
- (bool)isDark
|
|
{
|
|
double r, g, b;
|
|
[_backgroundGradientTop getRed:&r green:&g blue:&b alpha:NULL];
|
|
if (r > 0.25) return false;
|
|
if (g > 0.25) return false;
|
|
if (b > 0.25) return false;
|
|
return true;
|
|
}
|
|
|
|
- (UIImage *)imageNamed:(NSString *)name
|
|
{
|
|
UIImage *ret = _imageOverrides[name].self ?: [UIImage imageNamed:name];
|
|
if (!ret) {
|
|
if ([name isEqual:@"buttonA"] || [name isEqual:@"buttonB"]) {
|
|
return [self imageNamed:@"button"];
|
|
}
|
|
if ([name isEqual:@"buttonAPressed"] || [name isEqual:@"buttonBPressed"]) {
|
|
return [self imageNamed:@"buttonPressed"];
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
- (UIImage *)horizontalPreview
|
|
{
|
|
if (_horizontalPreview) return _horizontalPreview;
|
|
_renderingPreview = true;
|
|
GBLayout *layout = [[GBHorizontalLayout alloc] initWithTheme:self cutoutOnRight:false];
|
|
_renderingPreview = false;
|
|
GBBackgroundView *view = [[GBBackgroundView alloc] initWithLayout:layout];
|
|
[view enterPreviewMode:false];
|
|
view.usesSwipePad = [[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipePad"];
|
|
view.layout = layout;
|
|
view.bounds = CGRectMake(0, 0,
|
|
MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height),
|
|
MIN(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height));
|
|
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:(CGSize){view.bounds.size.width / 8,
|
|
view.bounds.size.height / 8,
|
|
}];
|
|
return _horizontalPreview = [renderer imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) {
|
|
CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1 / 8.0, 1 / 8.0);
|
|
[view.layer renderInContext:rendererContext.CGContext];
|
|
}];
|
|
}
|
|
|
|
- (UIImage *)verticalPreview
|
|
{
|
|
if (_verticalPreview) return _verticalPreview;
|
|
_renderingPreview = true;
|
|
GBLayout *layout = [[GBVerticalLayout alloc] initWithTheme:self];
|
|
_renderingPreview = false;
|
|
GBBackgroundView *view = [[GBBackgroundView alloc] initWithLayout:layout];
|
|
[view enterPreviewMode:false];
|
|
view.usesSwipePad = [[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipePad"];
|
|
view.layout = layout;
|
|
view.bounds = CGRectMake(0, 0,
|
|
MIN(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height),
|
|
MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height));
|
|
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:(CGSize){view.bounds.size.width / 8,
|
|
view.bounds.size.height / 8,
|
|
}];
|
|
return _verticalPreview = [renderer imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) {
|
|
CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1 / 8.0, 1 / 8.0);
|
|
[view.layer renderInContext:rendererContext.CGContext];
|
|
}];
|
|
}
|
|
|
|
@end
|