// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build darwin // +build ios #include "_cgo_export.h" #include #include #include #import #import struct utsname sysInfo; @interface GoAppAppController : GLKViewController @end @interface GoAppAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) GoAppAppController *controller; @end @implementation GoAppAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { lifecycleAlive(); self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.controller = [[GoAppAppController alloc] initWithNibName:nil bundle:nil]; self.window.rootViewController = self.controller; [self.window makeKeyAndVisible]; return YES; } - (void)applicationDidBecomeActive:(UIApplication * )application { lifecycleFocused(); } - (void)applicationWillResignActive:(UIApplication *)application { lifecycleVisible(); } - (void)applicationDidEnterBackground:(UIApplication *)application { lifecycleAlive(); } - (void)applicationWillTerminate:(UIApplication *)application { lifecycleDead(); } @end @interface GoAppAppController () @property (strong, nonatomic) EAGLContext *context; @property (strong, nonatomic) GLKView *glview; @end @implementation GoAppAppController - (void)viewWillAppear:(BOOL)animated { // TODO: replace by swapping out GLKViewController for a UIVIewController. [super viewWillAppear:animated]; self.paused = YES; } - (void)viewDidLoad { [super viewDidLoad]; self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; self.glview = (GLKView*)self.view; self.glview.drawableDepthFormat = GLKViewDrawableDepthFormat24; self.glview.multipleTouchEnabled = true; // TODO expose setting to user. self.glview.context = self.context; self.glview.userInteractionEnabled = YES; self.glview.enableSetNeedsDisplay = YES; // only invoked once // Do not use the GLKViewController draw loop. self.paused = YES; self.resumeOnDidBecomeActive = NO; self.preferredFramesPerSecond = 0; int scale = 1; if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)]) { scale = (int)[UIScreen mainScreen].scale; // either 1.0, 2.0, or 3.0. } setScreen(scale); CGSize size = [UIScreen mainScreen].bounds.size; UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; updateConfig((int)size.width, (int)size.height, orientation); } - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [coordinator animateAlongsideTransition:^(id context) { // TODO(crawshaw): come up with a plan to handle animations. } completion:^(id context) { UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; updateConfig((int)size.width, (int)size.height, orientation); }]; } - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { // Now that we have been asked to do the first draw, disable any // future draw and hand control over to the Go paint.Event cycle. self.glview.enableSetNeedsDisplay = NO; startloop((GLintptr)self.context); } #define TOUCH_TYPE_BEGIN 0 // touch.TypeBegin #define TOUCH_TYPE_MOVE 1 // touch.TypeMove #define TOUCH_TYPE_END 2 // touch.TypeEnd static void sendTouches(int change, NSSet* touches) { CGFloat scale = [UIScreen mainScreen].scale; for (UITouch* touch in touches) { CGPoint p = [touch locationInView:touch.view]; sendTouch((GoUintptr)touch, (GoUintptr)change, p.x*scale, p.y*scale); } } - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { sendTouches(TOUCH_TYPE_BEGIN, touches); } - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { sendTouches(TOUCH_TYPE_MOVE, touches); } - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { sendTouches(TOUCH_TYPE_END, touches); } - (void)touchesCanceled:(NSSet*)touches withEvent:(UIEvent*)event { sendTouches(TOUCH_TYPE_END, touches); } @end void runApp(void) { @autoreleasepool { UIApplicationMain(0, nil, nil, NSStringFromClass([GoAppAppDelegate class])); } } void makeCurrentContext(GLintptr context) { EAGLContext* ctx = (EAGLContext*)context; if (![EAGLContext setCurrentContext:ctx]) { // TODO(crawshaw): determine how terrible this is. Exit? NSLog(@"failed to set current context"); } } void swapBuffers(GLintptr context) { __block EAGLContext* ctx = (EAGLContext*)context; dispatch_sync(dispatch_get_main_queue(), ^{ [EAGLContext setCurrentContext:ctx]; [ctx presentRenderbuffer:GL_RENDERBUFFER]; }); } uint64_t threadID() { uint64_t id; if (pthread_threadid_np(pthread_self(), &id)) { abort(); } return id; }