GameView.mm 7.0 KB

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