I have used the legacy openGL with cocoa for years, but I'm now struggling to make the transition to openGL 3.2. There are several examples in the internet, but they are all too complex (and many don't even compile any more under XCode 5.1). Could someone write an example of the simplest, minimalistic, minimum cocoa code just to draw a read triangle to a NSOpenGLView? (no fancy shaders, no displayCallbacks, the fewer the code lines, the better).
Here's an answer based on the code in https://github.com/beelsebob/Cocoa-GL-Tutorial I changed these things: (1) The openGL context is created in a custom NSOpenGLView and not directly appended to the window. (2) I all the initialisation in one single function. (3) I deleted all the error verification code. This is not something you should do for a product, but I find it easier to understand the code with less clutter... (look at Cocoa-GL-Tutorial for proper error handling).
The steps (tested with Xcode 5.1):
MyOpenGLView.h
:#import <Cocoa/Cocoa.h> #import <OpenGL/OpenGL.h> #import <OpenGL/gl3.h> @interface MyOpenGLView : NSOpenGLView { GLuint shaderProgram; GLuint vertexArrayObject; GLuint vertexBuffer; GLint positionUniform; GLint colourAttribute; GLint positionAttribute; } @end
And this is the code for MyOpenGLView.m
:
#import "MyOpenGLView.h" @implementation MyOpenGLView - (id)initWithFrame:(NSRect)frame { // 1. Create a context with opengl pixel format NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = { NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, NSOpenGLPFAColorSize , 24 , NSOpenGLPFAAlphaSize , 8 , NSOpenGLPFADoubleBuffer , NSOpenGLPFAAccelerated , NSOpenGLPFANoRecovery , 0 }; NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes]; self = [super initWithFrame:frame pixelFormat:pixelFormat]; // 2. Make the context current [[self openGLContext] makeCurrentContext]; // 3. Define and compile vertex and fragment shaders GLuint vs; GLuint fs; const char *vss="#version 150\n\ uniform vec2 p;\ in vec4 position;\ in vec4 colour;\ out vec4 colourV;\ void main (void)\ {\ colourV = colour;\ gl_Position = vec4(p, 0.0, 0.0) + position;\ }"; const char *fss="#version 150\n\ in vec4 colourV;\ out vec4 fragColour;\ void main(void)\ {\ fragColour = colourV;\ }"; vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, 1, &vss, NULL); glCompileShader(vs); fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs, 1, &fss, NULL); glCompileShader(fs); printf("vs: %i, fs: %i\n",vs,fs); // 4. Attach the shaders shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vs); glAttachShader(shaderProgram, fs); glBindFragDataLocation(shaderProgram, 0, "fragColour"); glLinkProgram(shaderProgram); // 5. Get pointers to uniforms and attributes positionUniform = glGetUniformLocation(shaderProgram, "p"); colourAttribute = glGetAttribLocation(shaderProgram, "colour"); positionAttribute = glGetAttribLocation(shaderProgram, "position"); glDeleteShader(vs); glDeleteShader(fs); printf("positionUniform: %i, colourAttribute: %i, positionAttribute: %i\n",positionUniform,colourAttribute,positionAttribute); // 6. Upload vertices (1st four values in a row) and colours (following four values) GLfloat vertexData[]= { -0.5,-0.5,0.0,1.0, 1.0,0.0,0.0,1.0, -0.5, 0.5,0.0,1.0, 0.0,1.0,0.0,1.0, 0.5, 0.5,0.0,1.0, 0.0,0.0,1.0,1.0, 0.5,-0.5,0.0,1.0, 1.0,1.0,1.0,1.0}; glGenVertexArrays(1, &vertexArrayObject); glBindVertexArray(vertexArrayObject); glGenBuffers(1, &vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBufferData(GL_ARRAY_BUFFER, 4*8*sizeof(GLfloat), vertexData, GL_STATIC_DRAW); glEnableVertexAttribArray((GLuint)positionAttribute); glEnableVertexAttribArray((GLuint)colourAttribute ); glVertexAttribPointer((GLuint)positionAttribute, 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 0); glVertexAttribPointer((GLuint)colourAttribute , 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (char*)0+4*sizeof(GLfloat)); return self; } - (void)drawRect:(NSRect)dirtyRect { [super drawRect:dirtyRect]; glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shaderProgram); GLfloat p[]={0,0}; glUniform2fv(positionUniform, 1, (const GLfloat *)&p); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); [[self openGLContext] flushBuffer]; } @end
https://stackoverflow.com/a/22502999/4946861
In xcode 6.3.2 I got the example running afterreplacement of
(id)initWithFrame:(NSRect)frame
with(void)awakeFromNib
and replacement of
self = [super initWithFrame:frame pixelFormat:pixelFormat];
withsuper.pixelFormat=pixelFormat;
and deletion ofreturn self;
or written out in detail:
#import "MyOpenGLView.h"
@implementation MyOpenGLView
- (void)awakeFromNib
{
NSLog(@"...was here");
// 1. Create a context with opengl pixel format
NSOpenGLPixelFormatAttribute pixelFormatAttributes[] =
{
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFAColorSize , 24 ,
NSOpenGLPFAAlphaSize , 8 ,
NSOpenGLPFADoubleBuffer ,
NSOpenGLPFAAccelerated ,
NSOpenGLPFANoRecovery ,
0
};
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes];
super.pixelFormat=pixelFormat;
// 2. Make the context current
[[self openGLContext] makeCurrentContext];
// 3. Define and compile vertex and fragment shaders
GLuint vs;
GLuint fs;
const char *vss="#version 150\n\
uniform vec2 p;\
in vec4 position;\
in vec4 colour;\
out vec4 colourV;\
void main (void)\
{\
colourV = colour;\
gl_Position = vec4(p, 0.0, 0.0) + position;\
}";
const char *fss="#version 150\n\
in vec4 colourV;\
out vec4 fragColour;\
void main(void)\
{\
fragColour = colourV;\
}";
vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vss, NULL);
glCompileShader(vs);
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fss, NULL);
glCompileShader(fs);
printf("vs: %i, fs: %i\n",vs,fs);
// 4. Attach the shaders
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glBindFragDataLocation(shaderProgram, 0, "fragColour");
glLinkProgram(shaderProgram);
// 5. Get pointers to uniforms and attributes
positionUniform = glGetUniformLocation(shaderProgram, "p");
colourAttribute = glGetAttribLocation(shaderProgram, "colour");
positionAttribute = glGetAttribLocation(shaderProgram, "position");
glDeleteShader(vs);
glDeleteShader(fs);
printf("positionUniform: %i, colourAttribute: %i, positionAttribute: %i\n",positionUniform,colourAttribute,positionAttribute);
// 6. Upload vertices (1st four values in a row) and colours (following four values)
GLfloat vertexData[]= { -0.5,-0.5,0.0,1.0, 1.0,0.0,0.0,1.0,
-0.5, 0.5,0.0,1.0, 0.0,1.0,0.0,1.0,
0.5, 0.5,0.0,1.0, 0.0,0.0,1.0,1.0,
0.5,-0.5,0.0,1.0, 1.0,1.0,1.0,1.0};
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 4*8*sizeof(GLfloat), vertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray((GLuint)positionAttribute);
glEnableVertexAttribArray((GLuint)colourAttribute );
glVertexAttribPointer((GLuint)positionAttribute, 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 0);
glVertexAttribPointer((GLuint)colourAttribute , 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (char*)0+4*sizeof(GLfloat));
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
GLfloat p[]={0,0};
glUniform2fv(positionUniform, 1, (const GLfloat *)&p);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
[[self openGLContext] flushBuffer];
}
@end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With