OpenGL 3.0+ context setup in XCode4 using Lion

I am trying to set up an OpenGL 3.0+ context within XCode 4.

The apple developer website has some vague functionality changes(last updated 6/6/2011). Their shader examples are also listed as OpenGL 2.0. They do have a section but it really only gives you a table of extension changes and the old extensions that have been removed in the core.

I am trying to port all of my windows code using glut but I just haven’t been able to find examples of how to go into XCode4 and make everything work seamlessly. I actually have the 3rd edition of the Hillegass Mac OSX programming book but there is one section only about OpenGL and his code uses the fixed functionality pipeline.

I would appreciate it if anyone has any links that is dedicated on setting up an opengl context within Xcode 4 using OpenGL 3.0+.

I use the same code for both windows and mac (of course, checking for OpenGL version) and the context setup is pretty much the same.

I think XCode has nothing to do with the context setup since it is “just” an IDE.

What exactly are the problems you’re getting?

“Pretty much the same”? Really? What interface are you using? CGL? NSOpenGL is hardly identical to MS Windows.

There is at least one 3.2 demo from Apple, NSOpenGL-based. Hard to find though, but I can return with info about it once I get to the computer where I tested it. It worked but was too xib-dependent for my taste.

@Ragne - would appreciate the think to that demo when you get back. thanks! I really don’t understand apples lack of interest in opengl in general.

It’s not so much “lack of interest in OpenGL” as “lack of interest in MacOS”. When you’re making enough money to swim through Scrooge McDuck style on iPhones and iPads, what happens on your desktop platform just isn’t that important.

@Alfonse - do you have a link somewhere out there that deals with setting up opengl 3.0 context? that is NSOpenGLView based. not glut or glew or freeglut. thanks…

It would be easier to download GLFW (GLEW is a function loading library) and just read it’s source code to figure out how it works.

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.

Nobody tried it yet?

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.