gl_macos.m raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  // +build darwin,!ios
   4  
   5  @import AppKit;
   6  
   7  #include <CoreFoundation/CoreFoundation.h>
   8  #include <OpenGL/OpenGL.h>
   9  #include <OpenGL/gl3.h>
  10  #include "_cgo_export.h"
  11  
  12  static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFloat dy) {
  13  	NSPoint p = [view convertPoint:[event locationInWindow] fromView:nil];
  14  	if (!event.hasPreciseScrollingDeltas) {
  15  		// dx and dy are in rows and columns.
  16  		dx *= 10;
  17  		dy *= 10;
  18  	}
  19  	gio_onMouse((__bridge CFTypeRef)view, typ, [NSEvent pressedMouseButtons], p.x, p.y, dx, dy, [event timestamp], [event modifierFlags]);
  20  }
  21  
  22  @interface GioView : NSOpenGLView 
  23  @end
  24  
  25  @implementation GioView
  26  - (instancetype)initWithFrame:(NSRect)frameRect
  27  				  pixelFormat:(NSOpenGLPixelFormat *)format {
  28  	return [super initWithFrame:frameRect pixelFormat:format];
  29  }
  30  - (void)prepareOpenGL {
  31  	[super prepareOpenGL];
  32  	// Bind a default VBA to emulate OpenGL ES 2.
  33  	GLuint defVBA;
  34  	glGenVertexArrays(1, &defVBA);
  35  	glBindVertexArray(defVBA);
  36  	glEnable(GL_FRAMEBUFFER_SRGB);
  37  }
  38  - (BOOL)isFlipped {
  39  	return YES;
  40  }
  41  - (void)update {
  42  	[super update];
  43  	[self setNeedsDisplay:YES];
  44  }
  45  - (void)drawRect:(NSRect)r {
  46  	gio_onDraw((__bridge CFTypeRef)self);
  47  }
  48  - (void)mouseDown:(NSEvent *)event {
  49  	handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
  50  }
  51  - (void)mouseUp:(NSEvent *)event {
  52  	handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
  53  }
  54  - (void)middleMouseDown:(NSEvent *)event {
  55  	handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
  56  }
  57  - (void)middletMouseUp:(NSEvent *)event {
  58  	handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
  59  }
  60  - (void)rightMouseDown:(NSEvent *)event {
  61  	handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
  62  }
  63  - (void)rightMouseUp:(NSEvent *)event {
  64  	handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
  65  }
  66  - (void)mouseMoved:(NSEvent *)event {
  67  	handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0);
  68  }
  69  - (void)mouseDragged:(NSEvent *)event {
  70  	handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0);
  71  }
  72  - (void)scrollWheel:(NSEvent *)event {
  73  	CGFloat dx = -event.scrollingDeltaX;
  74  	CGFloat dy = -event.scrollingDeltaY;
  75  	handleMouse(self, event, GIO_MOUSE_SCROLL, dx, dy);
  76  }
  77  - (void)keyDown:(NSEvent *)event {
  78  	NSString *keys = [event charactersIgnoringModifiers];
  79  	gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], true);
  80  	[self interpretKeyEvents:[NSArray arrayWithObject:event]];
  81  }
  82  - (void)keyUp:(NSEvent *)event {
  83  	NSString *keys = [event charactersIgnoringModifiers];
  84  	gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], false);
  85  }
  86  - (void)insertText:(id)string {
  87  	const char *utf8 = [string UTF8String];
  88  	gio_onText((__bridge CFTypeRef)self, (char *)utf8);
  89  }
  90  - (void)doCommandBySelector:(SEL)sel {
  91  	// Don't pass commands up the responder chain.
  92  	// They will end up in a beep.
  93  }
  94  @end
  95  
  96  CFTypeRef gio_createGLView(void) {
  97  	@autoreleasepool {
  98  		NSOpenGLPixelFormatAttribute attr[] = {
  99  			NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
 100  			NSOpenGLPFAColorSize,     24,
 101  			NSOpenGLPFADepthSize,     16,
 102  			NSOpenGLPFAAccelerated,
 103  			// Opt-in to automatic GPU switching. CGL-only property.
 104  			kCGLPFASupportsAutomaticGraphicsSwitching,
 105  			NSOpenGLPFAAllowOfflineRenderers,
 106  			0
 107  		};
 108  		id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
 109  
 110  		NSRect frame = NSMakeRect(0, 0, 0, 0);
 111  		GioView* view = [[GioView alloc] initWithFrame:frame pixelFormat:pixFormat];
 112  
 113  		[view setWantsBestResolutionOpenGLSurface:YES];
 114  		[view setWantsLayer:YES]; // The default in Mojave.
 115  
 116  		return CFBridgingRetain(view);
 117  	}
 118  }
 119  
 120  void gio_setNeedsDisplay(CFTypeRef viewRef) {
 121  	NSOpenGLView *view = (__bridge NSOpenGLView *)viewRef;
 122  	[view setNeedsDisplay:YES];
 123  }
 124  
 125  CFTypeRef gio_contextForView(CFTypeRef viewRef) {
 126  	NSOpenGLView *view = (__bridge NSOpenGLView *)viewRef;
 127  	return (__bridge CFTypeRef)view.openGLContext;
 128  }
 129  
 130  void gio_clearCurrentContext(void) {
 131  	[NSOpenGLContext clearCurrentContext];
 132  }
 133  
 134  void gio_makeCurrentContext(CFTypeRef ctxRef) {
 135  	NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
 136  	[ctx makeCurrentContext];
 137  }
 138  
 139  void gio_lockContext(CFTypeRef ctxRef) {
 140  	NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
 141  	CGLLockContext([ctx CGLContextObj]);
 142  }
 143  
 144  void gio_unlockContext(CFTypeRef ctxRef) {
 145  	NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
 146  	CGLUnlockContext([ctx CGLContextObj]);
 147  }
 148