Skip to content

Instantly share code, notes, and snippets.

@possan
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save possan/5d044b3d418fee414b18 to your computer and use it in GitHub Desktop.
Save possan/5d044b3d418fee414b18 to your computer and use it in GitHub Desktop.
Minimal self container OpenGL Example on OSX
//
// Minimal self container OpenGL Example
//
// Compile with:
// xcrun gcc -o test -framework Foundation -framework OpenGL -framework CoreGraphics -framework AppKit main.m
//
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl.h>
#import <Carbon/Carbon.h>
#import <CoreFoundation/CoreFoundation.h>
#import <AppKit/AppKit.h>
#include <math.h>
@class MyWindow;
@interface MyRunner : NSObject
@property (nonatomic, readwrite) float time;
@property (nonatomic, readwrite) NSOpenGLContext *ctx;
@property (nonatomic, readwrite) MyWindow *window;
- (id)init;
- (void)doTick: (NSTimer*)timer;
@end
@interface MyWindow : NSWindow
@property (nonatomic, readwrite) MyRunner *runner;
@end
@implementation MyWindow
#define KEY_F 3
#define KEY_ESCAPE 53
#define KEY_RETURN 36
#define KEY_TAB 48
#define KEY_SPACE 49
#define KEY_Q 12
- (void) postCreate {
[self setLevel:NSMainMenuWindowLevel+1];
[self setOpaque:YES];
[self makeKeyAndOrderFront:nil];
CGLEnable((CGLContextObj)[self.runner.ctx CGLContextObj], kCGLCEMPEngine);
[self.runner.ctx setView:self.contentView];
[self.runner.ctx makeCurrentContext];
}
- (void) keyDown: (NSEvent*)ev {
if ([ev isARepeat])
return;
NSLog(@"key down: %d", [ev keyCode]);
if ([ev keyCode] == KEY_F || [ev keyCode] == KEY_RETURN) {
//
// Toggle fullscreen with 'F' or Return
//
if (self.styleMask & NSTitledWindowMask) {
NSLog(@"Go fullscreen...");
[self setStyleMask: NSFullScreenWindowMask ];
[self makeKeyAndOrderFront:nil];
NSRect viewRect = NSMakeRect(0.0, 0.0, self.screen.frame.size.width, self.screen.frame.size.height);
[self setFrame:viewRect display:YES];
[self.contentView setFrame:viewRect];
[self.runner.ctx setView:self.contentView];
[self.runner.ctx update];
} else {
NSLog(@"Go windowed...");
[self setStyleMask: NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask ];
NSRect viewRect = NSMakeRect(0.0, 0.0, 800, 600);
[self setFrame:viewRect display:YES];
[self.contentView setFrame:viewRect];
[self.runner.ctx setView:self.contentView];
[self makeKeyAndOrderFront:nil];
[self center];
[self.runner.ctx update];
}
}
if ([ev keyCode] == KEY_ESCAPE || [ev keyCode] == KEY_Q) {
//
// quit with 'Q' or Escape
//
[NSApp stop:nil];
[NSApp postEvent: [NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint modifierFlags:0 timestamp:0.0 windowNumber:0 context:NULL subtype:0 data1:0 data2:0] atStart:NO];
}
if ([ev keyCode] == KEY_SPACE) {
self.runner.time = (float) (rand() % 10000);
}
}
@end
@implementation MyRunner
- (id) init {
self = [super init];
self.time = .0f;
NSOpenGLPixelFormatAttribute attrs[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAScreenMask,
(NSOpenGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID()),
NSOpenGLPFADepthSize,
(NSOpenGLPixelFormatAttribute)16,
(NSOpenGLPixelFormatAttribute)0
};
NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: attrs];
self.ctx = [[NSOpenGLContext alloc] initWithFormat: fmt shareContext: nil];
NSRect viewRect = NSMakeRect(0, 0, 800, 600);
unsigned style = NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask;
self.window = [[MyWindow alloc] initWithContentRect: viewRect styleMask:style backing:NSBackingStoreBuffered defer:YES];
self.window.runner = self;
[self.window postCreate];
[self.window center];
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
[NSTimer scheduledTimerWithTimeInterval: 1.0f / 60.0f target:self selector: @selector(doTick:) userInfo: nil repeats: YES];
return self;
}
- (void) doTick: (NSTimer*)timer {
float T = self.time;
self.time += 1.0 / 60.0f;
GLint value = 1;
[self.ctx setValues: &value
forParameter: NSOpenGLCPSwapInterval];
NSRect viewRect = ((NSView *)self.window.contentView).frame;
glViewport(0,0, viewRect.size.width,viewRect.size.height);
glClearColor(0.1f + 0.1f * sin(T * 2.0f), 0.1f + 0.1f * sin(T * 3.0f), 0.1f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glBegin(GL_LINES);
glColor3f(0.1, 0.1, 0.1);
glVertex3f(-1,-1,0);
glVertex3f(1,1,0);
glVertex3f(1,-1,0);
glVertex3f(-1,1,0);
for(int k=0; k<30; k++) {
float z = (float)(k - 10 + fmod(T, 1.0)) / 10.0f;
glVertex3f(-1,z,0);
glVertex3f(1,z,0);
glVertex3f(z,-1,0);
glVertex3f(z,1,0);
}
for(int k=0; k<100; k++) {
float z = (float)k / 100.0;
glColor3f(z,z,z);
float x, y;
float T2 = T + (float)k / 100.0;
float C1 = T / 333.0;
float C2 = T / 100.0 + (float)k / 430.0;
x = sin(T2 * 3.1 + C2) * cos(T2 * 2.4 + C1);
y = cos(T2 * 3.9 + C2) * sin(T2 * 2.2 + C2);
glVertex3f(x,y,0);
x = sin(T2 * 3.7 + C1) * cos(T2 * 1.3 + C2);
y = cos(T2 * 3.6 + C1) * sin(T2 * 1.1 + C2);
glVertex3f(x,y,0);
}
glEnd();
[self.ctx flushBuffer];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
[NSApplication sharedApplication];
[MyRunner new];
[NSApp run];
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment