It wasn’t Apple’s, it was a third party demo:
https://github.com/beelsebob
It did run, but I didn’t like that it was xib based. I made my own instead, nibless. Here is a preliminary version, with quite a bit of remains of two other demos (one of my own, one of someone else):
// Based on the Cocoa variant of the "minimal animation" demo
// Working, reasonably simple 3.2 demo!!!
// Preliminary demo by Ingemar Ragnemalm 2012
// for the 3.2 update of my course book.
// Partially based on other GL3.2 demos, especially that demo with two triangles.
// (Should be referenced I guess but I can't do that right now.)
// Later versions appears in my book.
#import <Cocoa/Cocoa.h>
#include <OpenGL/gl3.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
// Globals
// Data would normally be read from files
GLfloat vertices[] = { -1.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f };
GLfloat colours[] = { 1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f };
GLfloat vertices2[] = { 0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f,
1.0f,0.0f,0.0f };
// two vertex array objects, one for each object drawn
unsigned int vertexArrayObjID[2];
// three vertex buffer objects in this example
unsigned int vertexBufferObjID[3];
// Note: free data afterwards.
char* loadFile(char *filename, GLint *fSize)
{
char * data;
FILE *theFile;
char c;
long howMuch;
// Get file length
theFile = fopen(filename, "rb");
if (theFile == NULL)
{
printf("%s not found
", filename);
return NULL;
}
howMuch = 0;
c = 0;
while (c != EOF)
{
c = getc(theFile);
howMuch++;
}
fclose(theFile);
printf("%ld bytes
", howMuch);
// Read it again
data = (char *)malloc(howMuch);
theFile = fopen(filename, "rb");
fread(data, howMuch-1,1,theFile);
fclose(theFile);
data[howMuch-1] = 0;
printf("
--- Shader source %s ---
%s
-- end of %s --
", filename, data, filename);
printf("%s loaded from disk
", filename);
*fSize = howMuch;
return data;
}
void dumpInfo(void)
{
printf ("Vendor: %s
", glGetString (GL_VENDOR));
printf ("Renderer: %s
", glGetString (GL_RENDERER));
printf ("Version: %s
", glGetString (GL_VERSION));
printf ("GLSL: %s
", glGetString (GL_SHADING_LANGUAGE_VERSION));
checkError ("dumpInfo");
}
/* report GL errors, if any, to stderr */
void checkError(const char *functionName)
{
GLenum error;
while (( error = glGetError() ) != GL_NO_ERROR)
{
fprintf (stderr, "GL error 0x%X detected in %s
", error, functionName);
}
}
// printShaderInfoLog
// From OpenGL Shading Language 3rd Edition, p215-216
// Display (hopefully) useful error messages if shader fails to compile
void printShaderInfoLog(GLint shader)
{
GLint infoLogLen = 0;
GLsizei charsWritten = 0;
GLchar *infoLog;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
// should additionally check for OpenGL errors here
if (infoLogLen > 0)
{
infoLog = (GLchar *)malloc(infoLogLen); //new GLchar[infoLogLen];
// error check for fail to allocate memory omitted
glGetShaderInfoLog(shader,infoLogLen, &charsWritten, infoLog);
printf("Infolog: %s
", infoLog);
free(infoLog);
}
else
printf("No infolog
");
// should additionally check for OpenGL errors here
}
void init(void)
{
// GL inits
glClearColor(0.2,0.2,0.5,0);
glEnable(GL_DEPTH_TEST);
checkError("GL inits");
// Would load objects from file here - but using globals in this example
// Allocate Vertex Array Objects
glGenVertexArrays(2, &vertexArrayObjID[0]);
// Setup first Vertex Array Object
glBindVertexArray(vertexArrayObjID[0]);
glGenBuffers(2, vertexBufferObjID);
// VBO for vertex data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[0]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
// VBO for colour data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[1]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(GLfloat), colours, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
// Setup second Vertex Array Object
glBindVertexArray(vertexArrayObjID[1]);
glGenBuffers(1, &vertexBufferObjID[2]);
// VBO for vertex data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[2]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(GLfloat), vertices2, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
checkError("init");
}
void initShaders(void)
{
GLuint p, f, v;
char *vs,*fs;
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
// load shaders & get length of each
GLint vlen;
GLint flen;
vs = loadFile("minimal.vert", &vlen);
fs = loadFile("minimal.frag", &flen);
const char * vv = vs;
const char * ff = fs;
glShaderSource(v, 1, &vv, NULL); // &vlen);
glShaderSource(f, 1, &ff, NULL); // &flen);
GLint compiled;
glCompileShader(v);
glGetShaderiv(v, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
printf("Vertex shader not compiled.
");
printShaderInfoLog(v);
}
glCompileShader(f);
glGetShaderiv(f, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
printf("Fragment shader not compiled.
");
printShaderInfoLog(f);
printf("-----
");
}
p = glCreateProgram();
glBindAttribLocation(p,0, "in_Position");
glBindAttribLocation(p,1, "in_Color");
glAttachShader(p,v);
glAttachShader(p,f);
glLinkProgram(p);
glUseProgram(p);
free(vs); // dont forget to free allocated memory
free(fs); // we allocated this in the loadFile function...
checkError("init shader");
}
void display(void)
{
checkError("pre display");
// clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vertexArrayObjID[0]); // First VAO
glDrawArrays(GL_TRIANGLES, 0, 3); // draw first object
glBindVertexArray(vertexArrayObjID[1]); // select second VAO
glVertexAttrib3f((GLuint)1, 1.0, 0.0, 0.0); // set constant color attribute
glDrawArrays(GL_TRIANGLES, 0, 3); // draw second object
glBindVertexArray(0);
checkError("display");
}
void reshape(int w, int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
}
// -----------
// Globals (was in GLViewDataPtr)
NSOpenGLContext *m_context;
float lastWidth, lastHeight;
NSView *theView;
void MakeContext(NSView *view)
{
// NSWindow *w;
NSOpenGLPixelFormat *fmt;
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 32,
0
};
// Create custom data pointer
theView = view;
// Init GL context
fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: &attrs];
m_context = [[NSOpenGLContext alloc] initWithFormat: fmt shareContext: nil];
[fmt release];
[m_context makeCurrentContext];
checkError("makeCurrentContext");
}
// -------------------- View ------------------------
@interface TestView : NSView { }
-(void)drawRect:(NSRect)rect;
@end
float loop;
#define Pi 3.1415
@implementation TestView
-(void)drawRect:(NSRect)rect
{
if (([theView frame].size.width != lastWidth) || ([theView frame].size.height != lastHeight))
{
lastWidth = [theView frame].size.width;
lastHeight = [theView frame].size.height;
// Only needed on resize:
[m_context clearDrawable];
reshape([theView frame].size.width, [theView frame].size.height);
}
[m_context setView: theView];
[m_context makeCurrentContext];
// Draw
display();
[m_context flushBuffer];
[NSOpenGLContext clearCurrentContext];
loop = loop + 0.1;
}
-(void)windowWillClose:(NSNotification *)note
{
[[NSApplication sharedApplication] terminate:self];
}
@end
// -------------------- Timer ------------------------
// Mini-mini class for the timer
@interface TimerController : NSObject { }
-(void)timerFireMethod:(NSTimer *)t;
@end
NSTimer *gTimer;
TimerController *myTimerController;
NSView *view;
// Timer!
@implementation TimerController
-(void)timerFireMethod:(NSTimer *)t;
{
[view setNeedsDisplay: YES];
}
@end
// home()
#include <Carbon/Carbon.h>
#include <stdio.h>
void home()
{
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
char path[PATH_MAX];
if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX))
{
// error!
return;
}
CFRelease(resourcesURL);
chdir(path);
printf("Current Path: %s
", path);
}
// ------------------ Main program ---------------------
NSApplication *myApp;
NSView *view;
NSAutoreleasePool *pool;
NSWindow *window;
int main(int argc, const char *argv[])
{
pool = [NSAutoreleasePool new];
myApp = [NSApplication sharedApplication];
home();
NSRect frame = NSMakeRect(10., 1000., 400., 400.);
window = [NSWindow alloc];
[window initWithContentRect:frame
styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask
backing:NSBackingStoreBuffered
defer:false];
[window setTitle:@"Minimal OpenGL animation (Cocoa)"];
view = [TestView alloc];
[view initWithFrame: frame];
// OpenGL init!
MakeContext(view);
init ();
initShaders();
dumpInfo ();
[window setContentView: view];
[window setDelegate: view];
[window makeKeyAndOrderFront: nil];
// Timer
myTimerController = [TimerController alloc];
gTimer = [NSTimer
scheduledTimerWithTimeInterval: 0.02
target: myTimerController
selector: @selector(timerFireMethod:)
userInfo: nil
repeats: YES];
// Main loop
[myApp run];
[pool release]; // Free;
return( EXIT_SUCCESS );
}
Vertex Shader
#version 150
in vec3 in_Position;
in vec3 in_Color;
out vec3 ex_Color;
void main(void)
{
ex_Color = in_Color;
gl_Position = vec4(in_Position, 1.0);
}
Fragment Shader
#version 150
in vec3 ex_Color;
out vec4 out_Color;
void main(void)
{
out_Color = vec4(ex_Color,1.0);
}
This should run pretty nicely. It does for me. Any problems, I can fix them.