GameView.mm 6.6 KB

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