git.y1.nz

SameBoy

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

iOS/GBLayout.m

      1 #define GBLayoutInternal
      2 #import "GBLayout.h"
      3 
      4 static double StatusBarHeight(void)
      5 {
      6     static double ret = 0;
      7     static dispatch_once_t onceToken;
      8     dispatch_once(&onceToken, ^{
      9         @autoreleasepool {
     10             UIWindow *window = [[UIWindow alloc] init];
     11             [window makeKeyAndVisible];
     12             UIEdgeInsets insets = window.safeAreaInsets;
     13             ret = MAX(MAX(insets.left, insets.right), MAX(insets.top, insets.bottom)) ?: 20;
     14             [window setHidden:true];
     15             if (!ret && [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
     16                 ret = 32; // iPadOS is buggy af
     17             }
     18         }
     19     });
     20     return ret;
     21 }
     22 
     23 static bool HasHomeBar(void)
     24 {
     25     static bool ret = false;
     26     static dispatch_once_t onceToken;
     27     dispatch_once(&onceToken, ^{
     28         ret = [UIApplication sharedApplication].windows[0].safeAreaInsets.bottom;
     29     });
     30     return ret;
     31 }
     32 
     33 @implementation GBLayout
     34 {
     35     bool _isRenderingMask;
     36 }
     37 
     38 - (instancetype)initWithTheme:(GBTheme *)theme
     39 {
     40     self = [super init];
     41     if (!self) return nil;
     42     
     43     _theme = theme;
     44     _factor = [UIScreen mainScreen].scale;
     45     _resolution = [UIScreen mainScreen].bounds.size;
     46     _resolution.width *= _factor;
     47     _resolution.height *= _factor;
     48     if (_resolution.width > _resolution.height) {
     49         _resolution = (CGSize){_resolution.height, _resolution.width};
     50     }
     51     
     52     _minY = StatusBarHeight() * _factor;
     53     _cutout = (_minY <= 24 * _factor || [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)? 0 : _minY;
     54     
     55     if (HasHomeBar()) {
     56         _homeBar =  21 * _factor;
     57     }
     58     
     59     // The Plus series will scale things lossily anyway, so no need to bother with integer scale things
     60     // This also "catches" zoomed display modes
     61     _hasFractionalPixels = _factor != [UIScreen mainScreen].nativeScale;
     62     return self;
     63 }
     64 
     65 - (CGRect)viewRectForOrientation:(UIInterfaceOrientation)orientation
     66 {
     67     return CGRectMake(0, 0, self.background.size.width / self.factor, self.background.size.height / self.factor);
     68 }
     69 
     70 - (void)drawBackground
     71 {
     72     CGContextRef context = UIGraphicsGetCurrentContext();
     73     CGColorRef top = _theme.backgroundGradientTop.CGColor;
     74     CGColorRef bottom = _theme.backgroundGradientBottom.CGColor;
     75     CGColorRef colors[] = {top, bottom};
     76     CFArrayRef colorsArray = CFArrayCreate(NULL, (const void **)colors, 2, &kCFTypeArrayCallBacks);
     77     
     78     CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
     79     CGGradientRef gradient = CGGradientCreateWithColors(colorspace, colorsArray, NULL);
     80     CGContextDrawLinearGradient(context,
     81                                 gradient,
     82                                 (CGPoint){0, 0},
     83                                 (CGPoint){0, self.size.height},
     84                                 0);
     85 
     86     CFRelease(gradient);
     87     CFRelease(colorsArray);
     88     CFRelease(colorspace);
     89 }
     90 
     91 - (void)drawScreenBezels
     92 {
     93     CGContextRef context = UIGraphicsGetCurrentContext();
     94     CGColorRef top = _theme.bezelsGradientTop.CGColor;
     95     CGColorRef bottom = _theme.bezelsGradientBottom.CGColor;
     96     CGColorRef colors[] = {top, bottom};
     97     CFArrayRef colorsArray = CFArrayCreate(NULL, (const void **)colors, 2, &kCFTypeArrayCallBacks);
     98     
     99     double borderWidth = MIN(self.screenRect.size.width / 40, 16 * _factor);
    100     CGRect bezelRect = self.screenRect;
    101     bezelRect.origin.x -= borderWidth;
    102     bezelRect.origin.y -= borderWidth;
    103     bezelRect.size.width += borderWidth * 2;
    104     bezelRect.size.height += borderWidth * 2;
    105     
    106     if (bezelRect.origin.y + bezelRect.size.height >= self.size.height - _homeBar) {
    107         bezelRect.origin.y = -32;
    108         bezelRect.size.height = self.size.height + 32;
    109     }
    110     UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:bezelRect cornerRadius:borderWidth];
    111     CGContextSaveGState(context);
    112     CGContextSetShadowWithColor(context, (CGSize){0, _factor}, _factor, [UIColor colorWithWhite:1 alpha:0.25].CGColor);
    113     [_theme.backgroundGradientBottom setFill];
    114     [path fill];
    115     [path addClip];
    116     
    117     CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    118     CGGradientRef gradient = CGGradientCreateWithColors(colorspace, colorsArray, NULL);
    119     CGContextDrawLinearGradient(context,
    120                                 gradient,
    121                                 bezelRect.origin,
    122                                 (CGPoint){bezelRect.origin.x, bezelRect.origin.y + bezelRect.size.height},
    123                                 0);
    124     
    125     CGContextSetShadowWithColor(context, (CGSize){0, _factor}, _factor, [UIColor colorWithWhite:0 alpha:0.25].CGColor);
    126     
    127     path.usesEvenOddFillRule = true;
    128     [path appendPath:[UIBezierPath bezierPathWithRect:(CGRect){{0, 0}, self.size}]];
    129     [path fill];
    130     
    131     
    132     CGContextRestoreGState(context);
    133     
    134     CGContextSaveGState(context);
    135     CGContextSetShadowWithColor(context, (CGSize){0, 0}, borderWidth / 4, [UIColor colorWithWhite:0 alpha:0.125].CGColor);
    136     
    137     [[UIColor blackColor] setFill];
    138     UIRectFill(self.screenRect);
    139     CGContextRestoreGState(context);
    140     
    141     CFRelease(gradient);
    142     CFRelease(colorsArray);
    143     CFRelease(colorspace);
    144 }
    145 
    146 - (void)drawLogoInVerticalRange:(NSRange)range controlPadding:(double)padding
    147 {
    148     UIFont *font = [UIFont fontWithName:@"AvenirNext-BoldItalic" size:range.length * 4 / 3];
    149     
    150     CGRect rect = CGRectMake(0,
    151                              range.location - range.length / 3,
    152                              self.size.width, range.length * 2);
    153     if (self.size.width > self.size.height) {
    154         rect.origin.x += _cutout / 2;
    155     }
    156     NSMutableParagraphStyle *style = [NSParagraphStyle defaultParagraphStyle].mutableCopy;
    157     style.alignment = NSTextAlignmentCenter;
    158     [@"SAMEBOY" drawInRect:rect
    159             withAttributes:@{
    160                 NSFontAttributeName: font,
    161                 NSForegroundColorAttributeName:_isRenderingMask? [UIColor whiteColor] : _theme.brandColor,
    162                 NSParagraphStyleAttributeName: style,
    163             }];
    164     
    165     _logoRect = (CGRect){
    166         {(self.size.width - _screenRect.size.width) / 2 + padding, rect.origin.y},
    167         {_screenRect.size.width - padding * 2, rect.size.height}
    168     };
    169 }
    170 
    171 - (void)drawThemedLabelsWithBlock:(void (^)(void))block
    172 {
    173     // Start with a normal normal pass
    174     block();
    175 }
    176 
    177 - (void)drawRotatedLabel:(NSString *)label withFont:(UIFont *)font origin:(CGPoint)origin distance:(double)distance
    178 {
    179     CGContextRef context = UIGraphicsGetCurrentContext();
    180     
    181     CGContextSaveGState(context);
    182     CGContextConcatCTM(context, CGAffineTransformMakeTranslation(origin.x, origin.y));
    183     CGContextConcatCTM(context, CGAffineTransformMakeRotation(-M_PI / 6));
    184 
    185     NSMutableParagraphStyle *style = [NSParagraphStyle defaultParagraphStyle].mutableCopy;
    186     style.alignment = NSTextAlignmentCenter;
    187 
    188     [label drawInRect:CGRectMake(-256, distance, 512, 256)
    189             withAttributes:@{
    190                 NSFontAttributeName: font,
    191                 NSForegroundColorAttributeName:_isRenderingMask? [UIColor whiteColor] : _theme.brandColor,
    192                 NSParagraphStyleAttributeName: style,
    193             }];
    194     CGContextRestoreGState(context);
    195 }
    196 
    197 - (void)drawLabels
    198 {
    199 
    200     UIFont *labelFont = [UIFont fontWithName:@"AvenirNext-Bold" size:24 * _factor];
    201     UIFont *smallLabelFont = [UIFont fontWithName:@"AvenirNext-DemiBold" size:20 * _factor];
    202     
    203     [self drawRotatedLabel:@"A" withFont:labelFont origin:self.aLocation distance:40 * self.factor];
    204     [self drawRotatedLabel:@"B" withFont:labelFont origin:self.bLocation distance:40 * self.factor];
    205     [self drawRotatedLabel:@"SELECT" withFont:smallLabelFont origin:self.selectLocation distance:24 * self.factor];
    206     [self drawRotatedLabel:@"START" withFont:smallLabelFont origin:self.startLocation distance:24 * self.factor];
    207 }
    208 
    209 - (CGSize)buttonDeltaForMaxHorizontalDistance:(double)maxDistance
    210 {
    211     CGSize buttonsDelta = {90 * self.factor, 45 * self.factor};
    212     if (buttonsDelta.width <= maxDistance) {
    213         return buttonsDelta;
    214     }
    215     return (CGSize){maxDistance, floor(sqrt(100 * 100 * self.factor * self.factor - maxDistance * maxDistance))};
    216 }
    217 
    218 - (CGSize)size
    219 {
    220     return _resolution;
    221 }
    222 @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.