GameView.mm 7.4 KB

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