GameScene.mm 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. //
  2. // GameScene.m
  3. // danmaku
  4. //
  5. // Created by Sam Jaffe on 5/22/19.
  6. // Copyright © 2019 Sam Jaffe. All rights reserved.
  7. //
  8. #import "GameScene.h"
  9. #include <OpenGL/gl3.h>
  10. #include "game/engine/events.hpp"
  11. #include "game/engine/game_dispatch.hpp"
  12. namespace env { namespace detail {
  13. extern void resize_screen(math::vec2i const&);
  14. }}
  15. @implementation GameScene {
  16. engine::game_dispatch game;
  17. };
  18. - (id)initWithFrame:(NSRect)aRect {
  19. NSOpenGLPixelFormatAttribute attr[] = {
  20. NSOpenGLPFADoubleBuffer,
  21. 0
  22. };
  23. // create pixel format
  24. NSOpenGLPixelFormat *nsglFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
  25. // create the context...
  26. if (!(self = [super initWithFrame:aRect pixelFormat:nsglFormat])) {
  27. return nil;
  28. }
  29. // make the context current
  30. [[self openGLContext] makeCurrentContext];
  31. // rest of your init method ...
  32. return self;
  33. }
  34. - (void)prepareOpenGL {
  35. // Renderer::GetInstance().Clear();
  36. // enable vertical sychronization to refresh rate
  37. const GLint vals = 0x01;
  38. [[self openGLContext] setValues:&vals forParameter:NSOpenGLCPSwapInterval];
  39. const GLint opaque = 0;
  40. [[self openGLContext] setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
  41. }
  42. - (void)drawRect:(NSRect)dirtyRect {
  43. // glClear(GL_COLOR_BUFFER_BIT);
  44. // glLoadIdentity();
  45. env::detail::resize_screen({{(int)dirtyRect.size.width,
  46. (int)dirtyRect.size.height}});
  47. game.render();
  48. // glFlush();
  49. // the correct way to do double buffering on Mac is this:
  50. [[self openGLContext] flushBuffer];
  51. int err;
  52. if ((err = glGetError()) != 0) {
  53. NSLog(@"glGetError(): %d", err);
  54. }
  55. }
  56. - (void)reshape {
  57. NSRect newFrame = {0, 0, [[self window] frame].size.width,
  58. [[self window] frame].size.height};
  59. [self setFrame:newFrame];
  60. // window resize; width and height are in pixel coordinates
  61. // but they are floats
  62. float screen_w = [self frame].size.width;
  63. float screen_h = [self frame].size.height;
  64. // glViewport(0,0, screen_w, screen_h);
  65. // here I cast floats to ints; most systems use integer coordinate systems
  66. env::detail::resize_screen({{(int)screen_w, (int)screen_h}});
  67. }
  68. - (BOOL)acceptsFirstResponder {
  69. return YES;
  70. }
  71. - (void) press_key:(int)key forEvent:(NSEvent *)evt ns_key:(int)local
  72. down:(BOOL)pressed {
  73. if ([evt keyCode] == local) {
  74. game.process_key_event(key, pressed);
  75. }
  76. }
  77. - (void) toggle_key:(int)key forEvent:(NSEvent *)evt ns_key:(int)local {
  78. NSUInteger flags = [evt modifierFlags] &
  79. NSEventModifierFlagDeviceIndependentFlagsMask;
  80. game.process_key_event(key, flags & local);
  81. }
  82. - (void)keyDown:(NSEvent *)theEvent {
  83. if ([theEvent isARepeat])
  84. return;
  85. NSString *str = [theEvent charactersIgnoringModifiers];
  86. unichar c = [str characterAtIndex:0];
  87. // only ASCII please
  88. if (c < ' ' || c > '~') {
  89. c = 0;
  90. }
  91. //(unsigned long)[theEvent modifierFlags]
  92. using namespace engine::keys;
  93. [self toggle_key:MOD_SHIFT forEvent:theEvent
  94. ns_key:NSEventModifierFlagShift];
  95. [self toggle_key:MOD_CONTROL forEvent:theEvent
  96. ns_key:NSEventModifierFlagControl];
  97. [self toggle_key:MOD_ALT forEvent:theEvent
  98. ns_key:NSEventModifierFlagOption];
  99. [self toggle_key:MOD_COMMAND forEvent:theEvent
  100. ns_key:NSEventModifierFlagCommand];
  101. [self press_key:UP_ARROW forEvent:theEvent ns_key:0x007e down:YES];
  102. [self press_key:DOWN_ARROW forEvent:theEvent ns_key:0x007d down:YES];
  103. [self press_key:LEFT_ARROW forEvent:theEvent ns_key:0x007b down:YES];
  104. [self press_key:RIGHT_ARROW forEvent:theEvent ns_key:0x007c down:YES];
  105. // NSLog(@"keyDown -> { 0x%04x, 0x%08lx, 0x%02x=%c }", [theEvent keyCode], [theEvent modifierFlags], c, c);
  106. game.process_key_event(c, true);
  107. }
  108. - (void)keyUp:(NSEvent *)theEvent {
  109. // NSLog(@"keyUp -> { 0x%04x, 0x%08lx }", [theEvent keyCode], [theEvent modifierFlags]);
  110. NSString *str = [theEvent charactersIgnoringModifiers];
  111. unichar c = [str characterAtIndex:0];
  112. // only ASCII please
  113. if (c < ' ' || c > '~') {
  114. c = 0;
  115. }
  116. using namespace engine::keys;
  117. [self press_key:UP_ARROW forEvent:theEvent ns_key:0x007e down:NO];
  118. [self press_key:DOWN_ARROW forEvent:theEvent ns_key:0x007d down:NO];
  119. [self press_key:LEFT_ARROW forEvent:theEvent ns_key:0x007b down:NO];
  120. [self press_key:RIGHT_ARROW forEvent:theEvent ns_key:0x007c down:NO];
  121. game.process_key_event(c, false);
  122. }
  123. static NSTimer *timer = nil;
  124. static NSTimer *frameTimer = nil;
  125. static NSTimeInterval const FRAME_INTERVAL = 1.0 / 60.0;
  126. - (void)windowDidResignMain:(NSNotification *)notification {
  127. NSLog(@"window did resign main");
  128. [timer invalidate];
  129. [frameTimer invalidate];
  130. // env::pause_clock();
  131. [self setNeedsDisplay:YES];
  132. }
  133. - (void)windowDidBecomeMain:(NSNotification *)notification {
  134. NSLog(@"window did become main");
  135. // env::resume_clock();
  136. [self setNeedsDisplay:YES];
  137. // TODO (sjaffe): Become able to change framerate
  138. // TODO (sjaffe): Link this with env::fps::v60, etc.
  139. timer = [NSTimer timerWithTimeInterval:FRAME_INTERVAL
  140. target:self
  141. selector:@selector(timerEvent:)
  142. userInfo:nil
  143. repeats:YES];
  144. frameTimer = [NSTimer timerWithTimeInterval:FRAME_INTERVAL
  145. target:self
  146. selector:@selector(renderEvent:)
  147. userInfo:nil
  148. repeats:YES];
  149. [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
  150. [[NSRunLoop currentRunLoop] addTimer:frameTimer forMode:NSDefaultRunLoopMode];
  151. }
  152. - (void)renderEvent:(NSTimer *)t {
  153. game.render();
  154. [[self openGLContext] flushBuffer];
  155. }
  156. - (void)timerEvent:(NSTimer *)t {
  157. game.update();
  158. [self setNeedsDisplay:YES];
  159. }
  160. - (void) awakeFromNib
  161. {
  162. NSOpenGLPixelFormatAttribute attributes [] = {
  163. NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24,
  164. NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
  165. (NSOpenGLPixelFormatAttribute)0
  166. };
  167. NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
  168. [self setPixelFormat:pf];
  169. }
  170. @end