#import "GLView.h" #include #include #include #include #include #include #include #include #include #ifdef KINC_OPENGL #include #endif static const int touchmaxcount = 20; static void *touches[touchmaxcount]; static void initTouches(void) { for (int i = 0; i < touchmaxcount; ++i) { touches[i] = NULL; } } static int getTouchIndex(void *touch) { for (int i = 0; i < touchmaxcount; ++i) { if (touches[i] == touch) return i; } return -1; } static int addTouch(void *touch) { for (int i = 0; i < touchmaxcount; ++i) { if (touches[i] == NULL) { touches[i] = touch; return i; } } return -1; } static int removeTouch(void *touch) { for (int i = 0; i < touchmaxcount; ++i) { if (touches[i] == touch) { touches[i] = NULL; return i; } } return -1; } static GLint backingWidth, backingHeight; int kinc_window_width(int window) { return backingWidth; } int kinc_window_height(int window) { return backingHeight; } @implementation GLView #ifdef KINC_METAL + (Class)layerClass { return [CAMetalLayer class]; } #else + (Class)layerClass { return [CAEAGLLayer class]; } #endif #ifdef KINC_OPENGL extern int kinc_ios_gl_framebuffer; #endif #ifdef KINC_METAL - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:(CGRect)frame]; self.contentScaleFactor = [UIScreen mainScreen].scale; backingWidth = frame.size.width * self.contentScaleFactor; backingHeight = frame.size.height * self.contentScaleFactor; initTouches(); device = MTLCreateSystemDefaultDevice(); commandQueue = [device newCommandQueue]; library = [device newDefaultLibrary]; CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer; metalLayer.device = device; metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; metalLayer.framebufferOnly = YES; // metalLayer.presentsWithTransaction = YES; metalLayer.opaque = YES; metalLayer.backgroundColor = nil; return self; } #else - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:(CGRect)frame]; self.contentScaleFactor = [UIScreen mainScreen].scale; backingWidth = frame.size.width * self.contentScaleFactor; backingHeight = frame.size.height * self.contentScaleFactor; initTouches(); CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = YES; eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; if (!context || ![EAGLContext setCurrentContext:context]) { //[self release]; return nil; } glGenFramebuffersOES(1, &defaultFramebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer); kinc_ios_gl_framebuffer = defaultFramebuffer; glGenRenderbuffersOES(1, &colorRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer); glGenRenderbuffersOES(1, &depthStencilRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthStencilRenderbuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthStencilRenderbuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthStencilRenderbuffer); // Start acceletometer hasAccelerometer = false; #ifndef KINC_TVOS motionManager = [[CMMotionManager alloc] init]; if ([motionManager isAccelerometerAvailable]) { motionManager.accelerometerUpdateInterval = 0.033; [motionManager startAccelerometerUpdates]; hasAccelerometer = true; } #endif #ifndef KINC_TVOS [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardHide:) name:UIKeyboardWillHideNotification object:nil]; #endif return self; } #endif #ifdef KINC_METAL - (void)begin { } #else - (void)begin { [EAGLContext setCurrentContext:context]; // glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer); // glViewport(0, 0, backingWidth, backingHeight); #ifndef KINC_TVOS // Accelerometer updates if (hasAccelerometer) { CMAcceleration acc = motionManager.accelerometerData.acceleration; if (acc.x != lastAccelerometerX || acc.y != lastAccelerometerY || acc.z != lastAccelerometerZ) { kinc_internal_on_acceleration(acc.x, acc.y, acc.z); lastAccelerometerX = acc.x; lastAccelerometerY = acc.y; lastAccelerometerZ = acc.z; } } #endif } #endif #ifdef KINC_METAL - (void)end { } #else - (void)end { glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES]; // crash at end } #endif void kinc_internal_call_resize_callback(int window, int width, int height); #ifdef KINC_METAL - (void)layoutSubviews { backingWidth = self.frame.size.width * self.contentScaleFactor; backingHeight = self.frame.size.height * self.contentScaleFactor; CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer; metalLayer.drawableSize = CGSizeMake(backingWidth, backingHeight); kinc_internal_call_resize_callback(0, backingWidth, backingHeight); } #else - (void)layoutSubviews { glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer *)self.layer]; glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); printf("backingWitdh/Height: %i, %i\n", backingWidth, backingHeight); glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthStencilRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH24_STENCIL8_OES, backingWidth, backingHeight); if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); } kinc_internal_call_resize_callback(0, backingWidth, backingHeight); } #endif #ifdef KINC_METAL - (void)dealloc { } #else - (void)dealloc { if (defaultFramebuffer) { glDeleteFramebuffersOES(1, &defaultFramebuffer); defaultFramebuffer = 0; } if (colorRenderbuffer) { glDeleteRenderbuffersOES(1, &colorRenderbuffer); colorRenderbuffer = 0; } if (depthStencilRenderbuffer) { glDeleteRenderbuffersOES(1, &depthStencilRenderbuffer); depthStencilRenderbuffer = 0; } if ([EAGLContext currentContext] == context) [EAGLContext setCurrentContext:nil]; //[context release]; context = nil; //[super dealloc]; } #endif - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { int index = getTouchIndex((__bridge void *)touch); if (index == -1) index = addTouch((__bridge void *)touch); if (index >= 0) { CGPoint point = [touch locationInView:self]; float x = point.x * self.contentScaleFactor; float y = point.y * self.contentScaleFactor; if (index == 0) { kinc_internal_mouse_trigger_press(0, event.buttonMask == UIEventButtonMaskSecondary ? 1 : 0, x, y); } kinc_internal_surface_trigger_touch_start(index, x, y); if (touch.type == UITouchTypePencil) { kinc_internal_pen_trigger_press(0, x, y, 0.0); } } } } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { int index = getTouchIndex((__bridge void *)touch); if (index >= 0) { CGPoint point = [touch locationInView:self]; float x = point.x * self.contentScaleFactor; float y = point.y * self.contentScaleFactor; if (index == 0) { kinc_internal_mouse_trigger_move(0, x, y); } kinc_internal_surface_trigger_move(index, x, y); } } } - (void)touchesEstimatedPropertiesUpdated:(NSSet *)touches { for (UITouch *touch in touches) { if (touch.type == UITouchTypePencil) { CGPoint point = [touch locationInView:self]; float x = point.x * self.contentScaleFactor; float y = point.y * self.contentScaleFactor; kinc_internal_pen_trigger_move(0, x, y, touch.force); } } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { int index = removeTouch((__bridge void *)touch); if (index >= 0) { CGPoint point = [touch locationInView:self]; float x = point.x * self.contentScaleFactor; float y = point.y * self.contentScaleFactor; if (index == 0) { kinc_internal_mouse_trigger_release(0, event.buttonMask == UIEventButtonMaskSecondary ? 1 : 0, x, y); } kinc_internal_surface_trigger_touch_end(index, x, y); if (touch.type == UITouchTypePencil) { kinc_internal_pen_trigger_release(0, x, y, 0.0); } } } } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { int index = removeTouch((__bridge void *)touch); if (index >= 0) { CGPoint point = [touch locationInView:self]; float x = point.x * self.contentScaleFactor; float y = point.y * self.contentScaleFactor; if (index == 0) { kinc_internal_mouse_trigger_release(0, event.buttonMask == UIEventButtonMaskSecondary ? 1 : 0, x, y); } kinc_internal_surface_trigger_touch_end(index, x, y); if (touch.type == UITouchTypePencil) { kinc_internal_pen_trigger_release(0, x, y, 0.0); } } } } static NSString *keyboardstring; static UITextField *myTextField = NULL; static bool shiftDown = false; - (void)showKeyboard { [self becomeFirstResponder]; } - (void)hideKeyboard { [self resignFirstResponder]; } - (BOOL)hasText { return YES; } - (void)insertText:(NSString *)text { if ([text length] == 1) { unichar ch = [text characterAtIndex:[text length] - 1]; if (ch == 8212) ch = '_'; if (ch == L'\n') { kinc_internal_keyboard_trigger_key_down(KINC_KEY_RETURN); kinc_internal_keyboard_trigger_key_up(KINC_KEY_RETURN); return; } if (ch == L'.') { kinc_internal_keyboard_trigger_key_down(KINC_KEY_PERIOD); kinc_internal_keyboard_trigger_key_up(KINC_KEY_PERIOD); } else if (ch == L'%') { kinc_internal_keyboard_trigger_key_down(KINC_KEY_PERCENT); kinc_internal_keyboard_trigger_key_up(KINC_KEY_PERCENT); } else if (ch == L'(') { kinc_internal_keyboard_trigger_key_down(KINC_KEY_OPEN_PAREN); kinc_internal_keyboard_trigger_key_up(KINC_KEY_OPEN_PAREN); } else if (ch == L'&') { kinc_internal_keyboard_trigger_key_down(KINC_KEY_AMPERSAND); kinc_internal_keyboard_trigger_key_up(KINC_KEY_AMPERSAND); } else if (ch == L'$') { kinc_internal_keyboard_trigger_key_down(KINC_KEY_DOLLAR); kinc_internal_keyboard_trigger_key_up(KINC_KEY_DOLLAR); } else if (ch == L'#') { kinc_internal_keyboard_trigger_key_down(KINC_KEY_HASH); kinc_internal_keyboard_trigger_key_up(KINC_KEY_HASH); } else if (ch >= L'a' && ch <= L'z') { if (shiftDown) { kinc_internal_keyboard_trigger_key_up(KINC_KEY_SHIFT); shiftDown = false; } kinc_internal_keyboard_trigger_key_down(ch + KINC_KEY_A - L'a'); kinc_internal_keyboard_trigger_key_up(ch + KINC_KEY_A - L'a'); } else { if (!shiftDown) { kinc_internal_keyboard_trigger_key_down(KINC_KEY_SHIFT); shiftDown = true; } kinc_internal_keyboard_trigger_key_down(ch + KINC_KEY_A - L'A'); kinc_internal_keyboard_trigger_key_up(ch + KINC_KEY_A - L'A'); } kinc_internal_keyboard_trigger_key_press(ch); } } - (void)deleteBackward { kinc_internal_keyboard_trigger_key_down(KINC_KEY_BACKSPACE); kinc_internal_keyboard_trigger_key_up(KINC_KEY_BACKSPACE); } - (BOOL)canBecomeFirstResponder { return YES; } - (void)onKeyboardHide:(NSNotification *)notification { kinc_keyboard_hide(); } #ifdef KINC_METAL - (CAMetalLayer *)metalLayer { return (CAMetalLayer *)self.layer; } - (id)metalDevice { return device; } - (id)metalLibrary { return library; } - (id)metalQueue { return commandQueue; } #endif @end