// // GameScene.m // danmaku // // Created by Sam Jaffe on 5/22/19. // Copyright © 2019 Sam Jaffe. All rights reserved. // #import "GameScene.h" #include #include "game/engine/events.hpp" #include "GameAdaptor.h" @implementation GameScene - (id)initWithFrame:(NSRect)aRect { NSOpenGLPixelFormatAttribute attr[] = { NSOpenGLPFADoubleBuffer, 0 }; // create pixel format NSOpenGLPixelFormat *nsglFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; // create the context... if (!(self = [super initWithFrame:aRect pixelFormat:nsglFormat])) { return nil; } // make the context current [[self openGLContext] makeCurrentContext]; // rest of your init method ... return self; } - (void)prepareOpenGL { init_gl(); // enable vertical sychronization to refresh rate const GLint vals = 0x01; [[self openGLContext] setValues:&vals forParameter:NSOpenGLCPSwapInterval]; const GLint opaque = 0; [[self openGLContext] setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; } - (void)drawRect:(NSRect)dirtyRect { // glClear(GL_COLOR_BUFFER_BIT); // glLoadIdentity(); screen_resize((int)dirtyRect.size.width, (int)dirtyRect.size.height); draw_screen(); // glFlush(); // the correct way to do double buffering on Mac is this: [[self openGLContext] flushBuffer]; int err; if ((err = glGetError()) != 0) NSLog(@"glGetError(): %d", err); } - (void)reshape { NSRect newFrame = {0, 0, [[self window] frame].size.width, [[self window] frame].size.height}; [self setFrame:newFrame]; // window resize; width and height are in pixel coordinates // but they are floats float screen_w = [self frame].size.width; float screen_h = [self frame].size.height; // glViewport(0,0, screen_w, screen_h); // here I cast floats to ints; most systems use integer coordinate systems screen_resize((int)screen_w, (int)screen_h); } - (BOOL)acceptsFirstResponder { return YES; } void bind_key_up(NSEvent * evt, int ns_key, int key) { if ([evt keyCode] == ns_key) { key_up(key); } } void bind_key_down(NSEvent * evt, int ns_key, int key) { if ([evt keyCode] == ns_key) { key_down(key); } } void bind_key_toggle(NSEvent * evt, int ns_key, int key) { NSUInteger flags = [evt modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; if (flags & ns_key) { key_down(key); } else { key_up(key); } } - (void)keyDown:(NSEvent *)theEvent { if ([theEvent isARepeat]) return; NSString *str = [theEvent charactersIgnoringModifiers]; unichar c = [str characterAtIndex:0]; // only ASCII please if (c < ' ' || c > '~') { c = 0; } //(unsigned long)[theEvent modifierFlags] using namespace engine::keys; bind_key_toggle(theEvent, NSEventModifierFlagShift, MOD_SHIFT); bind_key_toggle(theEvent, NSEventModifierFlagControl, MOD_CONTROL); bind_key_toggle(theEvent, NSEventModifierFlagOption, MOD_ALT); bind_key_toggle(theEvent, NSEventModifierFlagCommand, MOD_COMMAND); bind_key_down(theEvent, 0x007e, UP_ARROW); bind_key_down(theEvent, 0x007d, DOWN_ARROW); bind_key_down(theEvent, 0x007b, LEFT_ARROW); bind_key_down(theEvent, 0x007c, RIGHT_ARROW); // NSLog(@"keyDown -> { 0x%04x, 0x%08lx, 0x%02x=%c }", [theEvent keyCode], [theEvent modifierFlags], c, c); key_down(c); } - (void)keyUp:(NSEvent *)theEvent { // NSLog(@"keyUp -> { 0x%04x, 0x%08lx }", [theEvent keyCode], [theEvent modifierFlags]); NSString *str = [theEvent charactersIgnoringModifiers]; unichar c = [str characterAtIndex:0]; // only ASCII please if (c < ' ' || c > '~') { c = 0; } using namespace engine::keys; bind_key_up(theEvent, 0x007e, UP_ARROW); bind_key_up(theEvent, 0x007d, DOWN_ARROW); bind_key_up(theEvent, 0x007b, LEFT_ARROW); bind_key_up(theEvent, 0x007c, RIGHT_ARROW); key_up(c); } static NSTimer *timer = nil; static NSTimer *frameTimer = nil; static NSTimeInterval const FRAME_INTERVAL = 1.0 / 60.0; - (void)windowDidResignMain:(NSNotification *)notification { NSLog(@"window did resign main"); [timer invalidate]; [frameTimer invalidate]; game_deactivate(); // freeze, pause [self setNeedsDisplay:YES]; } - (void)windowDidBecomeMain:(NSNotification *)notification { NSLog(@"window did become main"); game_activate(); [self setNeedsDisplay:YES]; timer = [NSTimer timerWithTimeInterval:FRAME_INTERVAL target:self selector:@selector(timerEvent:) userInfo:nil repeats:YES]; frameTimer = [NSTimer timerWithTimeInterval:FRAME_INTERVAL target:self selector:@selector(renderEvent:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer:frameTimer forMode:NSDefaultRunLoopMode]; } - (void)renderEvent:(NSTimer *)t { draw_screen(); // FIXME [[self openGLContext] flushBuffer]; } - (void)timerEvent:(NSTimer *)t { run_game(); [self setNeedsDisplay:YES]; } - (void) awakeFromNib { NSOpenGLPixelFormatAttribute attributes [] = { NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24, NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, (NSOpenGLPixelFormatAttribute)0 }; NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; [self setPixelFormat:pf]; } @end