2015-07-16 20:40:46 -04:00
|
|
|
//
|
2016-03-05 14:45:09 -05:00
|
|
|
// CSOpenGLView
|
2015-07-26 15:25:11 -04:00
|
|
|
// CLK
|
2015-07-16 20:40:46 -04:00
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 16/07/2015.
|
|
|
|
// Copyright © 2015 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
2016-03-05 14:45:09 -05:00
|
|
|
#import "CSOpenGLView.h"
|
2015-07-16 20:40:46 -04:00
|
|
|
@import CoreVideo;
|
2015-09-24 21:23:16 -04:00
|
|
|
@import GLKit;
|
2015-07-16 20:40:46 -04:00
|
|
|
|
2017-08-17 10:48:29 -04:00
|
|
|
@interface CSOpenGLView () <NSDraggingDestination>
|
|
|
|
@end
|
|
|
|
|
2016-03-05 14:45:09 -05:00
|
|
|
@implementation CSOpenGLView {
|
2016-02-04 22:28:50 -05:00
|
|
|
CVDisplayLinkRef _displayLink;
|
2017-09-20 19:59:34 -04:00
|
|
|
CGSize _backingSize;
|
2015-07-16 20:40:46 -04:00
|
|
|
}
|
|
|
|
|
2015-07-16 21:16:21 -04:00
|
|
|
- (void)prepareOpenGL
|
2015-07-16 20:40:46 -04:00
|
|
|
{
|
2015-07-16 21:16:21 -04:00
|
|
|
// Synchronize buffer swaps with vertical refresh rate
|
|
|
|
GLint swapInt = 1;
|
|
|
|
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
2015-07-16 20:40:46 -04:00
|
|
|
|
2015-07-16 21:16:21 -04:00
|
|
|
// Create a display link capable of being used with all active displays
|
2016-02-04 22:28:50 -05:00
|
|
|
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
|
2016-04-20 22:35:46 -04:00
|
|
|
|
2015-07-16 21:16:21 -04:00
|
|
|
// Set the renderer output callback function
|
2016-02-04 22:28:50 -05:00
|
|
|
CVDisplayLinkSetOutputCallback(_displayLink, DisplayLinkCallback, (__bridge void * __nullable)(self));
|
2016-03-03 22:12:31 -05:00
|
|
|
|
2015-07-16 21:16:21 -04:00
|
|
|
// Set the display link for the current renderer
|
|
|
|
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
|
|
|
|
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
|
2016-02-04 22:28:50 -05:00
|
|
|
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_displayLink, cglContext, cglPixelFormat);
|
2015-07-26 15:13:46 -04:00
|
|
|
|
2016-03-03 22:12:31 -05:00
|
|
|
// set the clear colour
|
2015-07-26 15:25:11 -04:00
|
|
|
[self.openGLContext makeCurrentContext];
|
2015-07-26 15:55:19 -04:00
|
|
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
2015-07-26 15:13:46 -04:00
|
|
|
|
2015-07-16 21:16:21 -04:00
|
|
|
// Activate the display link
|
2016-02-04 22:28:50 -05:00
|
|
|
CVDisplayLinkStart(_displayLink);
|
2015-07-16 21:16:21 -04:00
|
|
|
}
|
2015-07-16 20:40:46 -04:00
|
|
|
|
2015-07-26 23:50:43 -04:00
|
|
|
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
|
2015-07-16 21:16:21 -04:00
|
|
|
{
|
2016-04-20 22:35:46 -04:00
|
|
|
CSOpenGLView *const view = (__bridge CSOpenGLView *)displayLinkContext;
|
|
|
|
[view drawAtTime:now frequency:CVDisplayLinkGetActualOutputVideoRefreshPeriod(displayLink)];
|
2015-07-16 21:16:21 -04:00
|
|
|
return kCVReturnSuccess;
|
|
|
|
}
|
2015-07-27 21:15:10 -04:00
|
|
|
|
2016-04-20 22:35:46 -04:00
|
|
|
- (void)drawAtTime:(const CVTimeStamp *)now frequency:(double)frequency
|
2016-03-03 22:12:31 -05:00
|
|
|
{
|
2016-06-02 22:29:09 -04:00
|
|
|
// Draw the display now regardless of other activity.
|
|
|
|
[self drawViewOnlyIfDirty:YES];
|
2016-03-03 22:12:31 -05:00
|
|
|
}
|
|
|
|
|
2015-07-27 21:15:10 -04:00
|
|
|
- (void)invalidate
|
|
|
|
{
|
2016-02-04 22:28:50 -05:00
|
|
|
CVDisplayLinkStop(_displayLink);
|
2015-07-27 21:15:10 -04:00
|
|
|
}
|
|
|
|
|
2015-07-16 21:16:21 -04:00
|
|
|
- (void)dealloc
|
|
|
|
{
|
|
|
|
// Release the display link
|
2016-02-04 22:28:50 -05:00
|
|
|
CVDisplayLinkRelease(_displayLink);
|
2015-07-16 20:40:46 -04:00
|
|
|
}
|
|
|
|
|
2016-02-04 22:28:50 -05:00
|
|
|
- (CGSize)backingSize
|
2016-01-06 23:14:36 -05:00
|
|
|
{
|
2017-09-20 19:59:34 -04:00
|
|
|
@synchronized(self) {
|
|
|
|
return _backingSize;
|
|
|
|
}
|
2016-01-06 23:14:36 -05:00
|
|
|
}
|
|
|
|
|
2015-07-23 22:51:53 -04:00
|
|
|
- (void)reshape
|
|
|
|
{
|
|
|
|
[super reshape];
|
2017-09-20 19:59:34 -04:00
|
|
|
@synchronized(self) {
|
|
|
|
_backingSize = [self convertSizeToBacking:self.bounds.size];
|
|
|
|
}
|
2015-07-23 22:51:53 -04:00
|
|
|
|
2016-03-19 22:46:17 -04:00
|
|
|
[self performWithGLContext:^{
|
|
|
|
CGSize viewSize = [self backingSize];
|
|
|
|
glViewport(0, 0, (GLsizei)viewSize.width, (GLsizei)viewSize.height);
|
|
|
|
}];
|
2015-07-23 22:51:53 -04:00
|
|
|
}
|
|
|
|
|
2015-08-13 23:22:51 +01:00
|
|
|
- (void)awakeFromNib
|
2015-07-23 22:51:53 -04:00
|
|
|
{
|
|
|
|
NSOpenGLPixelFormatAttribute attributes[] =
|
|
|
|
{
|
|
|
|
NSOpenGLPFADoubleBuffer,
|
|
|
|
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
2016-02-27 22:46:31 -05:00
|
|
|
NSOpenGLPFAMultisample,
|
2015-09-10 21:30:39 -04:00
|
|
|
NSOpenGLPFASampleBuffers, 1,
|
2016-02-18 23:21:25 -05:00
|
|
|
NSOpenGLPFASamples, 2,
|
2015-07-23 22:51:53 -04:00
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
|
|
|
NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// When we're using a CoreProfile context, crash if we call a legacy OpenGL function
|
|
|
|
// This will make it much more obvious where and when such a function call is made so
|
|
|
|
// that we can remove such calls.
|
|
|
|
// Without this we'd simply get GL_INVALID_OPERATION error for calling legacy functions
|
|
|
|
// but it would be more difficult to see where that function was called.
|
|
|
|
CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
self.pixelFormat = pixelFormat;
|
|
|
|
self.openGLContext = context;
|
|
|
|
self.wantsBestResolutionOpenGLSurface = YES;
|
2017-08-17 10:48:29 -04:00
|
|
|
|
|
|
|
// Register to receive dragged and dropped file URLs.
|
|
|
|
[self registerForDraggedTypes:@[(__bridge NSString *)kUTTypeFileURL]];
|
2015-07-23 22:51:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-26 15:13:46 -04:00
|
|
|
- (void)drawRect:(NSRect)dirtyRect
|
2015-08-13 22:01:25 +01:00
|
|
|
{
|
2016-03-13 13:38:03 -04:00
|
|
|
[self drawViewOnlyIfDirty:NO];
|
2015-08-13 22:01:25 +01:00
|
|
|
}
|
|
|
|
|
2016-02-04 23:05:47 -05:00
|
|
|
- (void)drawViewOnlyIfDirty:(BOOL)onlyIfDirty
|
2016-03-19 22:46:17 -04:00
|
|
|
{
|
|
|
|
[self performWithGLContext:^{
|
|
|
|
[self.delegate openGLView:self drawViewOnlyIfDirty:onlyIfDirty];
|
|
|
|
CGLFlushDrawable([[self openGLContext] CGLContextObj]);
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)performWithGLContext:(dispatch_block_t)action
|
2015-07-26 15:13:46 -04:00
|
|
|
{
|
2015-08-13 22:01:25 +01:00
|
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
2016-03-19 22:54:56 -04:00
|
|
|
[self.openGLContext makeCurrentContext];
|
2016-03-19 22:46:17 -04:00
|
|
|
action();
|
2015-08-13 22:01:25 +01:00
|
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
2015-07-26 15:13:46 -04:00
|
|
|
}
|
|
|
|
|
2015-08-18 20:33:24 -04:00
|
|
|
#pragma mark - NSResponder
|
|
|
|
|
|
|
|
- (BOOL)acceptsFirstResponder
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)keyDown:(NSEvent *)theEvent
|
|
|
|
{
|
2016-03-19 22:46:17 -04:00
|
|
|
[self.responderDelegate keyDown:theEvent];
|
2015-08-18 20:33:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)keyUp:(NSEvent *)theEvent
|
|
|
|
{
|
2016-03-19 22:46:17 -04:00
|
|
|
[self.responderDelegate keyUp:theEvent];
|
2015-08-18 20:33:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)flagsChanged:(NSEvent *)theEvent
|
|
|
|
{
|
2016-03-19 22:46:17 -04:00
|
|
|
[self.responderDelegate flagsChanged:theEvent];
|
2015-08-18 20:33:24 -04:00
|
|
|
}
|
|
|
|
|
2017-08-17 10:48:29 -04:00
|
|
|
#pragma mark - NSDraggingDestination
|
|
|
|
|
|
|
|
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
|
|
|
|
{
|
|
|
|
for(NSPasteboardItem *item in [[sender draggingPasteboard] pasteboardItems])
|
|
|
|
{
|
|
|
|
NSURL *URL = [NSURL URLWithString:[item stringForType:(__bridge NSString *)kUTTypeFileURL]];
|
|
|
|
[self.delegate openGLView:self didReceiveFileAtURL:URL];
|
|
|
|
}
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender
|
|
|
|
{
|
|
|
|
// we'll drag and drop, yeah?
|
|
|
|
return NSDragOperationLink;
|
|
|
|
}
|
|
|
|
|
2015-07-16 20:40:46 -04:00
|
|
|
@end
|