git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

iOS/GBTheme.m

      1 #import "GBTheme.h"
      2 #import "GBVerticalLayout.h"
      3 #import "GBHorizontalLayout.h"
      4 #import "GBBackgroundView.h"
      5 
      6 @interface GBLazyObject : NSProxy
      7 @end
      8 
      9 @implementation GBLazyObject
     10 {
     11     id _target;
     12     id (^_constructor)(void);
     13 }
     14 
     15 
     16 - (instancetype)initWithConstructor:(id (^)(void))constructor
     17 {
     18     _constructor = constructor;
     19     return self;
     20 }
     21 
     22 - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
     23 {
     24     if (GB_likely(!_target)) {
     25         _target = _constructor();
     26         _constructor = nil;
     27     }
     28     return [_target methodSignatureForSelector:sel];
     29 }
     30 
     31 - (void)forwardInvocation:(NSInvocation *)invocation
     32 {
     33     if (GB_likely(!_target)) {
     34         _target = _constructor();
     35         _constructor = nil;
     36     }
     37     invocation.target = _target;
     38     [invocation invoke];
     39 }
     40 
     41 - (instancetype)self
     42 {
     43     if (GB_likely(!_target)) {
     44         _target = _constructor();
     45         _constructor = nil;
     46     }
     47     return _target;
     48 }
     49 
     50 @end
     51 
     52 #define MakeColor(r, g, b) [UIColor colorWithRed:(r) / 255.0 green:(g) / 255.0 blue:(b) / 255.0 alpha:1.0]
     53 
     54 __attribute__((objc_direct_members))
     55 @implementation GBTheme
     56 {
     57     NSDictionary<NSString *, UIImage *> *_imageOverrides;
     58     UIImage *_horizontalPreview;
     59     UIImage *_verticalPreview;
     60 }
     61 
     62 
     63 // Assumes the image has a purple hue
     64 + (UIImage *)_recolorImage:(UIImage *)image withColor:(UIColor *)color
     65 {
     66     double scale = image.scale;
     67     
     68     image = [UIImage imageWithCGImage:image.CGImage scale:1.0 orientation:UIImageOrientationUp];
     69 
     70     CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
     71     CIFilter *filter = [CIFilter filterWithName:@"CIColorMatrix"];
     72     double r, g, b;
     73     [color getRed:&r green:&g blue:&b alpha:NULL];
     74     
     75     [filter setDefaults];
     76     [filter setValue:ciImage forKey:@"inputImage"];
     77     
     78     [filter setValue:[CIVector vectorWithX:r * 1.34  Y:1 - r Z:0 W:0] forKey:@"inputRVector"];
     79     [filter setValue:[CIVector vectorWithX:g * 1.34  Y:1 - g Z:0 W:0] forKey:@"inputGVector"];
     80     [filter setValue:[CIVector vectorWithX:b * 1.34  Y:1 - b Z:0 W:0] forKey:@"inputBVector"];
     81     
     82     [filter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"];
     83     
     84 
     85     CIContext *context = [CIContext context];
     86     CGImageRef cgImage = [context createCGImage:filter.outputImage fromRect:filter.outputImage.extent];
     87     image = [UIImage imageWithCGImage:cgImage scale:scale orientation:0];
     88     CGImageRelease(cgImage);
     89 
     90     return image;
     91 }
     92 
     93 + (UIImage *)recolorImage:(UIImage *)image withColor:(UIColor *)color
     94 {
     95     return (id)[[GBLazyObject alloc] initWithConstructor:^id{
     96         return [self _recolorImage:image withColor:color];
     97     }];
     98 }
     99 
    100 - (instancetype)initDefaultTheme
    101 {
    102     self = [super init];
    103     
    104     _brandColor = [UIColor colorWithRed:0 / 255.0 green:70 / 255.0 blue:141 / 255.0 alpha:1.0];
    105     _backgroundGradientTop = [UIColor colorWithRed:192 / 255.0 green:195 / 255.0 blue:199 / 255.0 alpha:1.0];
    106     _backgroundGradientBottom = [UIColor colorWithRed:174 / 255.0 green:176 / 255.0 blue:180 / 255.0 alpha:1.0];
    107     
    108     _bezelsGradientTop = [UIColor colorWithWhite:53 / 255.0 alpha:1.0];
    109     _bezelsGradientBottom = [UIColor colorWithWhite:45 / 255.0 alpha:1.0];
    110     
    111     _name = @"SameBoy";
    112     
    113     return self;
    114 }
    115 
    116 - (void)setupBackgroundWithColor:(uint32_t)color
    117 {
    118     uint8_t r = color >> 16;
    119     uint8_t g = color >> 8;
    120     uint8_t b = color;
    121     
    122     _backgroundGradientTop = MakeColor(r, g, b);
    123     _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];
    124 }
    125 
    126 - (void)setupButtonsWithColor:(UIColor *)color
    127 {
    128     _imageOverrides = @{
    129         @"button": [GBTheme recolorImage:[UIImage imageNamed:@"button"] withColor:color],
    130         @"buttonPressed": [GBTheme recolorImage:[UIImage imageNamed:@"buttonPressed"] withColor:color],
    131         
    132         @"dpad": [GBTheme recolorImage:[UIImage imageNamed:@"dpad-tint"] withColor:color],
    133         @"swipepad": [GBTheme recolorImage:[UIImage imageNamed:@"swipepad-tint"] withColor:color],
    134         
    135         @"button2": [GBTheme recolorImage:[UIImage imageNamed:@"button2-tint"] withColor:color],
    136         @"button2Pressed": [GBTheme recolorImage:[UIImage imageNamed:@"button2Pressed-tint"] withColor:color],
    137     };
    138 }
    139 
    140 - (instancetype)initDarkTheme
    141 {
    142     self = [super init];
    143     
    144     [self setupBackgroundWithColor:0x181c23];
    145 
    146     _brandColor = [UIColor colorWithRed:0 / 255.0 green:70 / 255.0 blue:141 / 255.0 alpha:1.0];
    147     _bezelsGradientTop = [UIColor colorWithWhite:53 / 255.0 alpha:1.0];
    148     _bezelsGradientBottom = [UIColor colorWithWhite:45 / 255.0 alpha:1.0];
    149     
    150     [self setupButtonsWithColor:MakeColor(0x08, 0x0c, 0x12)];
    151 
    152     _name = @"SameBoy Dark";
    153     
    154     return self;
    155 }
    156 
    157 
    158 - (UIColor *)buttonColor
    159 {
    160     double r, g, b;
    161     [_brandColor getRed:&r green:&g blue:&b alpha:NULL];
    162     if (r == 1.0 && g == 1.0 && b == 1.0) {
    163         return _backgroundGradientTop;
    164     }
    165     return [UIColor colorWithRed:r green:g blue:b alpha:1.0];
    166 }
    167 
    168 - (bool)isDark
    169 {
    170     double r, g, b;
    171     [_backgroundGradientTop getRed:&r green:&g blue:&b alpha:NULL];
    172     if (r > 0.25) return false;
    173     if (g > 0.25) return false;
    174     if (b > 0.25) return false;
    175     return true;
    176 }
    177 
    178 - (UIImage *)imageNamed:(NSString *)name
    179 {
    180     UIImage *ret = _imageOverrides[name].self ?: [UIImage imageNamed:name];
    181     if (!ret) {
    182         if  ([name isEqual:@"buttonA"] || [name isEqual:@"buttonB"]) {
    183             return [self imageNamed:@"button"];
    184         }
    185         if  ([name isEqual:@"buttonAPressed"] || [name isEqual:@"buttonBPressed"]) {
    186             return [self imageNamed:@"buttonPressed"];
    187         }
    188     }
    189     return ret;
    190 }
    191 
    192 - (UIImage *)horizontalPreview
    193 {
    194     if (_horizontalPreview) return _horizontalPreview;
    195     _renderingPreview = true;
    196     GBLayout *layout = [[GBHorizontalLayout alloc] initWithTheme:self cutoutOnRight:false];
    197     _renderingPreview = false;
    198     GBBackgroundView *view = [[GBBackgroundView alloc] initWithLayout:layout];
    199     [view enterPreviewMode:false];
    200     view.usesSwipePad = [[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipePad"];
    201     view.layout = layout;
    202     view.bounds = CGRectMake(0, 0,
    203                              MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height),
    204                              MIN(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height));
    205     UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:(CGSize){view.bounds.size.width / 8,
    206         view.bounds.size.height / 8,
    207     }];
    208     return _horizontalPreview = [renderer imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) {
    209         CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1 / 8.0, 1 / 8.0);
    210         [view.layer renderInContext:rendererContext.CGContext];
    211     }];
    212 }
    213 
    214 - (UIImage *)verticalPreview
    215 {
    216     if (_verticalPreview) return _verticalPreview;
    217     _renderingPreview = true;
    218     GBLayout *layout = [[GBVerticalLayout alloc] initWithTheme:self];
    219     _renderingPreview = false;
    220     GBBackgroundView *view = [[GBBackgroundView alloc] initWithLayout:layout];
    221     [view enterPreviewMode:false];
    222     view.usesSwipePad = [[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipePad"];
    223     view.layout = layout;
    224     view.bounds = CGRectMake(0, 0,
    225                              MIN(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height),
    226                              MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height));
    227     UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:(CGSize){view.bounds.size.width / 8,
    228                                                                                                view.bounds.size.height / 8,
    229     }];
    230     return _verticalPreview = [renderer imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) {
    231         CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1 / 8.0, 1 / 8.0);
    232         [view.layer renderInContext:rendererContext.CGContext];
    233     }];
    234 }
    235 
    236 @end

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.