XCode C++ (Part 3)
Neil Haddley • March 8, 2023
Building an OpenGL application using C++ and XCode
I compiled an OpenGL Triangle app on my M1 MacBook Air.
The OpenGL Extension Wrangler Library (GLEW) is a cross-platform loading library.
GLEW provides a way to determine (at runtime) which OpenGL implementations are available.
The "4.1 Metal - 76.3" OpenGL implementation is available on my M1 MacBook Air.

Running application
Overview
The GLFW library is used to create an application window with a given width and height and the title "LearnOpenGL".
The GLEW library state is initialized.
A GLEW library call is used to define a viewport.
In this example vertex shader and fragment shader code (written in the C-like language GLSL) is copied, compiled and executed on the computer's graphics processing unit (GPU).
In a loop the shaders are used to draw and redraw a triangle defined by a set of positions/vertices. Each position includes an x value between -1 (far left) and 1 (far right), a y value between -1 (bottom) and 1 (top) and a z value (always 0 in this example).

brew install glew

Add include folder to header search

Add library

updated library references

build and run application
main.cpp
TEXT
1#include <iostream> 2 3// GLEW 4#define GLEW_STATIC 5#include <GL/glew.h> 6 7// GLFW 8#include <GLFW/glfw3.h> 9 10// Window dimensions 11const GLuint WIDTH = 800, HEIGHT = 600; 12 13// Shaders 14const GLchar* vertexShaderSource = "#version 330 core\n" 15"layout (location = 0) in vec3 position;\n" 16"void main()\n" 17"{\n" 18"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n" 19"}\0"; 20const GLchar* fragmentShaderSource = "#version 330 core\n" 21"out vec4 color;\n" 22"void main()\n" 23"{\n" 24"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" 25"}\n\0"; 26 27// The MAIN function, from here we start the application and run the game loop 28int main() 29{ 30 // Init GLFW 31 glfwInit( ); 32 33 // Set all the required options for GLFW 34 glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 ); 35 glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 ); 36 glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE ); 37 glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE ); 38 39 glfwWindowHint( GLFW_RESIZABLE, GL_FALSE ); 40 41 // Create a GLFWwindow object that we can use for GLFW's functions 42 GLFWwindow *window = glfwCreateWindow( WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr ); 43 44 int screenWidth, screenHeight; 45 glfwGetFramebufferSize( window, &screenWidth, &screenHeight ); 46 47 if ( nullptr == window ) 48 { 49 std::cout << "Failed to create GLFW window" << std::endl; 50 glfwTerminate( ); 51 52 return EXIT_FAILURE; 53 } 54 55 glfwMakeContextCurrent( window ); 56 57 // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions 58 glewExperimental = GL_TRUE; 59 // Initialize GLEW to setup the OpenGL Function pointers 60 if ( GLEW_OK != glewInit( ) ) 61 { 62 std::cout << "Failed to initialize GLEW" << std::endl; 63 return EXIT_FAILURE; 64 } 65 66 std::cout << glGetString(GL_VERSION); 67 68 // Define the viewport dimensions 69 glViewport( 0, 0, screenWidth, screenHeight ); 70 71 72 // Build and compile our shader program 73 // Vertex shader 74 GLuint vertexShader = glCreateShader( GL_VERTEX_SHADER ); 75 glShaderSource( vertexShader, 1, &vertexShaderSource, NULL ); 76 glCompileShader( vertexShader ); 77 78 // Check for compile time errors 79 GLint success; 80 GLchar infoLog[512]; 81 82 glGetShaderiv( vertexShader, GL_COMPILE_STATUS, &success ); 83 if ( !success ) 84 { 85 glGetShaderInfoLog( vertexShader, 512, NULL, infoLog ); 86 std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; 87 } 88 89 // Fragment shader 90 GLuint fragmentShader = glCreateShader( GL_FRAGMENT_SHADER ); 91 glShaderSource( fragmentShader, 1, &fragmentShaderSource, NULL ); 92 glCompileShader( fragmentShader ); 93 94 // Check for compile time errors 95 glGetShaderiv( fragmentShader, GL_COMPILE_STATUS, &success ); 96 97 if ( !success ) 98 { 99 glGetShaderInfoLog( fragmentShader, 512, NULL, infoLog ); 100 std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; 101 } 102 103 // Link shaders 104 GLuint shaderProgram = glCreateProgram( ); 105 glAttachShader( shaderProgram, vertexShader ); 106 glAttachShader( shaderProgram, fragmentShader ); 107 glLinkProgram( shaderProgram ); 108 109 // Check for linking errors 110 glGetProgramiv( shaderProgram, GL_LINK_STATUS, &success ); 111 112 if ( !success ) 113 { 114 glGetProgramInfoLog( shaderProgram, 512, NULL, infoLog ); 115 std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; 116 } 117 118 glDeleteShader( vertexShader ); 119 glDeleteShader( fragmentShader ); 120 121 122 // Set up vertex data (and buffer(s)) and attribute pointers 123 GLfloat vertices[] = 124 { 125 -0.5f, -0.5f, 0.0f, // Left 126 0.5f, -0.5f, 0.0f, // Right 127 0.0f, 0.5f, 0.0f // Top 128 }; 129 130 GLuint VBO, VAO; 131 glGenVertexArrays( 1, &VAO ); 132 glGenBuffers( 1, &VBO ); 133 // Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s). 134 glBindVertexArray( VAO ); 135 136 glBindBuffer( GL_ARRAY_BUFFER, VBO ); 137 glBufferData( GL_ARRAY_BUFFER, sizeof( vertices ), vertices, GL_STATIC_DRAW ); 138 139 glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof( GLfloat ), ( GLvoid * ) 0 ); 140 glEnableVertexAttribArray( 0 ); 141 142 glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind 143 144 glBindVertexArray( 0 ); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs) 145 146 // Game loop 147 while ( !glfwWindowShouldClose( window ) ) 148 { 149 // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions 150 glfwPollEvents( ); 151 152 // Render 153 // Clear the colorbuffer 154 glClearColor( 0.2f, 0.3f, 0.3f, 1.0f ); 155 glClear( GL_COLOR_BUFFER_BIT ); 156 157 // Draw our first triangle 158 glUseProgram( shaderProgram ); 159 glBindVertexArray( VAO ); 160 glDrawArrays( GL_TRIANGLES, 0, 3 ); 161 glBindVertexArray( 0 ); 162 163 // Swap the screen buffers 164 glfwSwapBuffers( window ); 165 } 166 167 // Properly de-allocate all resources once they've outlived their purpose 168 glDeleteVertexArrays( 1, &VAO ); 169 glDeleteBuffers( 1, &VBO ); 170 171 // Terminate GLFW, clearing any resources allocated by GLFW. 172 glfwTerminate( ); 173 174 return EXIT_SUCCESS; 175}