GameView.mm 7.6 KB

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