opengl-article-01

Welcome to the first of a series of articles about modern OpenGL, with a focus on making games. All the code will be open source, and downloadable from github: https://github.com/tomdalling/opengl-series.

By the end of this article, you will have a working OpenGL 3.2 project in Visual C++ on Windows, Xcode on OSX, and Linux. The app will have a vertex shader, a fragment shader, and will display a single triangle using a VAO and a VBO. The project will use GLEW to access the OpenGL API, GLFW to handle window creation and input, and GLM for matrix/vector math.

Yes, it is a little bit boring, but just getting a project set up correctly can be difficult, especially for beginners. Once this is out of the way we will get into the more interesting stuff.

Table of Contents

Accessing The Code

Download all lessons as a zip from here: https://github.com/tomdalling/opengl-series/archive/master.zip

All the code in this series of articles is available from github: https://github.com/tomdalling/opengl-series. You can download a zip of all the files from that page, or you can clone the repository if you are familiar with git.

The code for this article can be found in the windows/01_project_skeleton, osx/01_project_skeleton, and linux/01_project_skeleton directories. Setup instructions for Xcode, Visual C++, and Linux are coming up later in the article.

I would like to get an iOS version of these articles working, but I don’t have the time at the moment. If you would like to contribute an iOS port, I would be happy to include it in the github repository.

A Note On Compatibility

These articles use OpenGL 3.2, but I will try to keep the code compatible with:

  • OpenGL 2.1 for backwards compatibility
  • OpenGL 3.X and 4.X for forwards compatibility
  • OpenGL ES 2.0 for compatibility with Android and iOS

Because there are so many different versions of OpenGL and GLSL, the code won’t be 100% compatible with all the versions mentioned above. I hope for it to be 99% compatible, requiring only very minor changes when switching between versions. If you would like to tweak the project to run on a different version of OpenGL, I would be happy to include it in the github repository.

Too see the differences between the versions of OpenGL and GLSL, good compatibility tables are available here.

Visual C++ Setup Instructions

The VC++ project was created and tested on Windows 7 32bit, in Visual C++ Express 2010 (which is available for free). You should be able to just open the project and build it successfully, but if you can’t then please let me know, or send me a fix and I will update the project. The project comes with 32bit versions of GLFW, GLEW, and GLM, so you shouldn’t need to install anything extra.

Xcode Setup Instructions

The Xcode project was created and tested on OSX 10.8.3, in Xcode 4.6.1. You should be able to open each Xcode project and build it successfully, without any additional setup steps. GLM, GLEW, and GLFW are included in the directory osx/thirdparty. Please let me know if the Xcode project does not build successfully for you.

The projects are configured for 64-bit builds, which should be fine if your mac was purchased within the last five years or so. If you have a 32-bit-only mac that won’t build the project, send me a message and I’ll see what I can do.

Linux Setup Instructions

The linux port of this article was kindly provided by SpartanJ. I tested it quickly on Ubuntu 12.04.

  1. Install GLM, GLFW, and GLEW with: sudo aptitude install libglm-dev libglew-dev libglfw-dev
  2. Change into the directory of the project with: cd ~/Desktop/opengl-series/linux/01_project_skeleton
  3. Run the makefile with: make
  4. Run the executable with: bin/01_project_skeleton-debug

Introducing GLEW, GLFW, and GLM

Now that you have a working project, let’s start by introducing the open-source libraries that the project uses, and why they are necessary.

The OpenGL Extension Wrangler (GLEW) is what we will be using to give us access to the OpenGL 3.2 API functions. Unfortunately, accessing OpenGL functions isn’t as simple as #include <GL/gl.h> unless you want to use an ancient version of OpenGL. In modern OpenGL, the API functions are determined at run time, not compile time. GLEW will handle the run time loading of the OpenGL API.

GLFW will allow us to create a window, and receive mouse and keyboard input in a cross-platform way. OpenGL does not handle window creation or input, so this must be done somewhere else. I chose GLFW over the alternatives because it is very small, and easy to understand.

OpenGL Mathematics (GLM) is a mathematics library that handles vectors and matrices, amongst other things. Older versions of OpenGL provided functions like glRotate, glTranslate, and glScale, which would do some of the math for you. In modern OpenGL, the previously mentioned functions do not exist, and we must do all of the math ourselves. GLM will help a lot in future articles, when we start digging into vector and matrix math.

During this series of articles, we will also be making our own small library of reusable C++ code in the tdogl namespace. This article will include tdogl::Shader and tdogl::Program, which are used to load, compile, and link shaders.

What Are Shaders?

Shaders are an important concept in modern OpenGL. The application will not run without them, and the code won’t make much sense unless you understand what they are.

Shaders are little programs, made from GLSL code, that run on the GPU instead of the CPU.

Shaders are little programs, made from GLSL code, that run on the GPU instead of the CPU. They are written in OpenGL Shading Language (GLSL), which looks like C or C++, but it is a different language. The way you make a shader is similar to the way you make a normal program: you write the code, then you compile the code, then you link bits of compiled code together to make the final program.

“Shaders” is not a very good name for them, because they do a lot more than just shading. Just think of them as little programs, written in a different language, that will run on your graphics card.

In older version of OpenGL, shaders were optional. In modern OpenGL, shaders are required in order to get anything to show on the screen.

For a closer look at shaders and the graphics pipeline with nice pictures, I recommend The Graphics Pipeline chapter of the Durian Software series of articles.

Main Program Shader Program
Language C++ GLSL
Main function int main(int, char**); void main();
Runs on CPU GPU
Gets compiled? yes yes
Gets linked? yes yes

So what do shaders actually do? That depends on what type of shader they are.

Vertex Shaders

The main purpose of a vertex shader is to transform points (x, y, and z coordinates) into different points.

The main purpose of a vertex shader is to transform points (x, y, and z coordinates) into different points. A vertex is a is just a point in a shape. One point is called a “vertex”, and multiple points are called “vertices” (pronounced “ver-tuh-seez“). In this article, we have a triangle made of three vertices.

Here is the GLSL code for the vertex shader used in this article:

#version 150

in vec3 vert;

void main() {
    // does not alter the vertices at all
    gl_Position = vec4(vert, 1);
}

The first line #version 150 tells OpenGL that this shader is written in GLSL version 1.50.

The second line in vec3 vert; says that this shader takes a single vertex as input, into a variable named vert.

The third line defines a function called main, which is where the shader will begin running. This is the same as in C, except in GLSL main does not take any arguments and returns void.

The fourth line gl_Position = vec4(vert, 1); takes the input vertex and sends it straight to the output without modifying it at all. The variable gl_Position is a global defined by OpenGL, and is used to store the output of the vertex shader. All vertex shaders must set the gl_Position variable.

gl_Position is a 4D coordinate (vec4), but vert is a 3D coordinate (vec3), so we convert vert into a 4D coordinate with vec4(vert, 1). The second argument, 1, sets the value of the fourth dimension. We will learn more about 4D coordinates in later articles. For now, just know that if the fourth dimension is 1, then you can ignore the fourth dimension and treat it exactly the same as a 3D coordinate.

The vertex shader in this article doesn’t actually do anything, but in later articles we will be modifying it to handle animation, cameras, and other things.

Fragment Shaders

The main purpose of a fragment shader is to calculate the color of each pixel that is drawn.

The main purpose of a fragment shader is to calculate the color of each pixel that is drawn.

A “fragment” is basically a pixel, so you can think of fragment shaders as “pixel shaders.” In this article each fragment is a pixel, but this isn’t always true. If you change certain OpenGL settings you can get fragments that are smaller than pixels, but this is a topic for a later article.

Here is the GLSL code for the fragment shader used in this article:

#version 150

out vec4 finalColor;

void main() {
    //set every drawn pixel to white
    finalColor = vec4(1.0, 1.0, 1.0, 1.0);
}

Once again, the first line #version 150 tells OpenGL that this shader is written in GLSL version 1.50.

The second line out vec4 finalColor; declares an output variable that will hold the color of the pixel.

The fourth line finalColor = vec4(1.0, 1.0, 1.0, 1.0); sets the output variable to the color white. The part vec4(1.0, 1.0, 1.0, 1.0) creates an RGBA color, with the red, green, blue and alpha set to maximum, which means the color is white.

For now, everything that we draw in OpenGL will be pure white when we use this shader. In later articles, we will add colors and textures. Textures are images that you can put onto your 3D shapes.

Compiling And Linking Shaders

In C++, to make a program you first have to compile all the .cpp files, and then link them together to make the final program. OpenGL shaders work in the same way.

The code for this article contains two reusable classes that will handle the compilation and linking of shaders: tdogl::Shader and tdogl::Program. There isn’t much code in these two classes, and the code is documented with comments, so I suggest you read the code to understand how the OpenGL functions work.

What are VBOs and VAOs?

If shaders run on the GPU, and the rest of the C++ code runs on the CPU, you need a way of sending data from the CPU to the GPU. In this article, we are just sending the three points of a triangle, but in a larger project it would be thousands of points of a 3D model, colors, texture coordinates, and other things.

VBOs and VAOs are used to take data from your C++ program and send it through to the shaders for rendering.

This is where we need Vertex Buffer Objects (VBOs) and Vertex Array Objects (VAOs). VBOs and VAOs are used to take data from your C++ program and send it through to the shaders for rendering.

In older versions of OpenGL, this data was sent to the GPU every frame using functions like glVertex, glTexCoord and glNormal. In modern OpenGL, all of this data must be sent to the graphics card using VBOs before it is rendered. Then, when you actually want to render the data, you must set up VAOs that describe how to pull the data out of the VBOs and feed it into the shader variables.

Vertex Buffer Objects (VBOs)

VBOs are “buffers” of video memory – just a bunch of bytes containing any kind of binary data you want.

The first step to rendering our triangle is to upload (i.e. send) the three points from normal memory to the video memory on the graphics card. This is what VBOs are for. VBOs are “buffers” of video memory – just a bunch of bytes containing any kind of binary data you want. You can upload 3D points, colors, your music collection, poems to your loved ones – the VBO doesn’t care, because it just copies a chunk of memory without asking what the memory contains.

Vertex Array Objects (VAOs)

The second step to rendering our triangle is to send the points from the VBO into the shaders. Remember how the VBOs are just chunks of data, and have no idea what type of data they contain? Somehow you have to tell OpenGL what type of data is in the buffer, and this is what VAOs are for.

VAOs are the link between the VBOs and the shader variables. VAOs describe what type of data is contained within a VBO, and which shader variables the data should be sent to.

VAOs are the link between the VBOs and the shader variables. VAOs describe what type of data is contained within a VBO, and which shader variables the data should be sent to. Out of all the bad names in OpenGL, I think “Vertex Array Object” is one of the worst, because it doesn’t explain anything about what VAOs actually do.

If you look at the vertex shader we are using (shown earlier in the article), you will see that we only have one input variable called vert. In this article, we will use a VAO to say “hey OpenGL, this VBO right here has 3D points in it, and I want you to send those points to the ‘vert’ variable in the vertex shader.”

In later articles, we will use VAOs to say “hey OpenGL, this VBO right here has 3D points, some colors, and some texture coordinates all mixed together in a certain pattern. I want you to send the points to the ‘vert’ variable, the colors to the ‘vertColor’ variable, and the texture coordinates to the ‘vertTexCoord’ variable in the shader.”

A note for people with previous experience in OpenGL:

If you have used VBOs without VAOs in older versions of OpenGL, then you might not agree with this description of VAOs. You could argue that “vertex attributes” set by glVertexAttribPointer are the link between the VBO and that shaders, not VAOs. It depends on whether you consider the vertex attributes to be “inside” the VAO (which I do), or whether they are global state that is external to the VAO. Using the 3.2 core profile and my ATI drivers, the VAO is not optional – glEnableVertexAttribArray, glVertexAttribPointer and glDrawArrays all cause a GL_INVALID_OPERATION error if there is no VAO bound. This is what leads me to believe that the vertex attributes are inside the VAO, and not global state. The 3.2 core profile spec says that VAOs are required, but I hear that only ATI drivers throw errors if no VAO is bound. Here are some quotes from the OpenGL 3.2 core profile specification:

All state related to the definition of data used by the vertex processor is encapsulated in a vertex array object.

The currently bound vertex array object is used for all commands which modify vertex array state, such as VertexAttribPointer and EnableVertexAttribArray; all commands which draw from vertex arrays, such as DrawArrays and DrawElements; and all queries of vertex array state (see chapter 6).

However, I can see why vertex attributes could be considered to be external to VAOs. glVertexAttribPointer predates VAOs, so there was a time when vertex attributes were just global state. You could see VAOs as just a way to efficiently change that global state. I prefer to think of it like this: if you don’t create a VAO, then OpenGL provides a default global VAO. So when you use glVertexAttribPointer you are still modifying the vertex attributes inside a VAO, it’s just that you’re modifying the default VAO instead of one you created yourself.

There is a bit more of a discussion here: http://www.opengl.org/discussion_boards/showthread.php/174577-Questions-on-VAOs

Explaining The Code

Finally! The theory lesson is over and we can start digging into the code. OpenGL is not very beginner-friendly, but if you understand the concepts that have been explained so far in this article (shaders, VBOs, and VAOs) then you are doing well.

Open the file main.cpp (main.mm on OSX), and we will walk through the code starting at the main() function.

First, we initialise GLFW.

if(!glfwInit())
    throw std::runtime_error("glfwInit failed");

Next, we use GLFW to create a window. The window will contain an OpenGL 3.2 core profile context. This is the most “modern” version of OpenGL I can use on my hardware. According to the latest Steam hardware survey, over 80% of Steam users have a graphics card capable of OpenGL 3.2. If glfwOpenWindow is failing for you, then you may need to lower the OpenGL version.

glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2);
glfwOpenWindowHint(GLFW_WINDOW_NO_RESIZE, GL_TRUE);
if(!glfwOpenWindow(SCREEN_SIZE.x, SCREEN_SIZE.y, 8, 8, 8, 8, 0, 0, GLFW_WINDOW))
    throw std::runtime_error("glfwOpenWindow failed. Can your hardware handle OpenGL 3.2?");

Now that we have an OpenGL context available in our window, we initialise GLEW so that we get access to the OpenGL API functions.

glewExperimental = GL_TRUE; //stops glew crashing on OSX :-/
if(glewInit() != GLEW_OK)
    throw std::runtime_error("glewInit failed");

As of writing this, GLEW has a few issues with the OpenGL core profile we are using. Setting glewExperimental to true fixes the problem, but hopefully this won’t be necessary in the future.

We will also use GLEW to double-check that the 3.2 API is available:

if(!GLEW_VERSION_3_2)
    throw std::runtime_error("OpenGL 3.2 API is not available.");

Inside the LoadShaders function, we compile and link a vertex shader and a fragment shader using the tdogl::Shader and tdogl::Program classes provided with this article.

std::vector<tdogl::Shader> shaders;
shaders.push_back(tdogl::Shader::shaderFromFile(ResourcePath("vertex-shader.txt"), GL_VERTEX_SHADER));
shaders.push_back(tdogl::Shader::shaderFromFile(ResourcePath("fragment-shader.txt"), GL_FRAGMENT_SHADER));
gProgram = new tdogl::Program(shaders);

Inside the LoadTriangle function, we are going to make one VBO and one VAO. The first step is to create and bind the a new VAO:

glGenVertexArrays(1, &gVAO);
glBindVertexArray(gVAO);

Then we create and bind a new VBO:

glGenBuffers(1, &gVBO);
glBindBuffer(GL_ARRAY_BUFFER, gVBO);

Next, we upload some data into the new VBO. The data is going to be three points, where each point is three GLfloats.

GLfloat vertexData[] = {
    //  X     Y     Z
     0.0f, 0.8f, 0.0f,
    -0.8f,-0.8f, 0.0f,
     0.8f,-0.8f, 0.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

Now that the buffer contains the three points of our triangle, it is time to set up the VAO. First, we are going to enable the vert variable in the shader program. Variables can be enabled and disabled, and they are disabled by default, so we need to turn it on. The vert variable is an “attribute variable,” which is why the OpenGL functions have the word “Attrib” in their name. We will see a different type of variable in future articles.

glEnableVertexAttribArray(gProgram->attrib("vert"));

The most complicated part of VAO setup is this next function: glVertexAttribPointer. Let’s see the function call first, then I will explain each argument.

glVertexAttribPointer(gProgram->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 0, NULL);

The first argument, gProgram->attrib("vert"), is the shader variable that the data should be sent to. In this case, we want to send the data to the vert variable of our shader.

The second argument, 3, says that each vertex has three numbers.

The third argument, GL_FLOAT, says that the three numbers are GLfloats. This is important because if they were GLdoubles then the size of the data would be different.

The fourth argument, GL_FALSE, says that we do not want the floats to be “normalized.” If they were normalized, they would be restricted to having a minimum of zero, and a maximum of one. We don’t want that restriction on our points, which is why this argument is false.

The fifth argument, 0, would be used if there was a gap in between each point. Setting this argument to zero means that there are no gaps in our data.

The sixth argument, NULL, would be used if our data was not at the start of the buffer. Setting this argument to NULL means that our data starts right at the first byte of the VBO.

Now that the VBO and VAO are fully set up, we unbind them so they don’t accidentally get used somewhere else:

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

At this point, the shaders, VBO, and VAO are ready for use. All we have to do now is draw them inside the Render function.

First we clear the screen so that it is completely black:

glClearColor(0, 0, 0, 1); // black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Next we tell OpenGL that we want to start using our shaders and our VAO:

glUseProgram(gProgram->object());
glBindVertexArray(gVAO);

At last, we can draw that ever-elusive triangle:

glDrawArrays(GL_TRIANGLES, 0, 3);

This call to glDrawArrays says that we want to draw triangles, starting at vertex zero, and ending after three vertices have been sent to the shader. It will look at the currently bound VAO to determine where to get the vertices from.

The vertices will be pulled out of the VBO and sent to the vertex shader. Then each pixel within the triangle will be sent to the fragment shader. Then, the fragment shader will make each pixel white. Hooray!

The drawing is finished now, so we unbind the shaders and the VAO just to be safe:

glBindVertexArray(0);
glUseProgram(0);

The last thing that needs to be done before we can see the triangle is to swap the frame buffers:

glfwSwapBuffers();

Before the frame buffers were swapped, we were drawing to an off-screen frame buffer that was not visible in the window we created at the start. When we call glfwSwapBuffers the off-screen buffer becomes an on-screen buffer, so that we can see it in the window.

Future Article Sneak Peek

In the next article we will texture the triangle with an image. In the article after that we will learn a bit about matrix transformation, and use it in the vertex shader to make a cube spin in 3D.

After that, we will start creating a 3D scene with a camera and multiple objects.

Additional Modern OpenGL Resources

Unfortunately, I had to skim over a lot of topics in order to stop this article from becoming the size of a textbook. Quench your thirst for knowledge with these fine modern OpenGL resources:

  • Casey

    Great article. It’s a great intro to OpenGL.

  • Holland Schutte

    Simple, concise, and to the point. +1.

  • Inigo Lheredia

    Nice work. I’m actually following Jason L. McKesson’s “Learning Modern 3D Graphics Programming “. What will this tutorial series contribute to that reading?

  • IamAguest

    This is actually pretty good. I love the yellow boxes that give a quick summary of the important details.

  • Guest#1

    Hey, thanks for this! Look forward to seeing the other parts. I’m gonna save them until the semester is over!

  • http://www.tomdalling.com/ Tom Dalling

    That is certainly a good book. I’m trying to make my articles a little bit more beginner-friendly, and with more of an emphasis on playing with working code each article.

  • Mike

    The Windows version will not run on Windows 7 64-bit.  It compiles with the following message:

    1>—— Rebuild All started: Project: 01_project_skeleton, Configuration: Debug Win32 ——
    1>  Shader.cpp
    1>  Program.cpp
    1>  main.cpp
    1>  Generating Code…
    1>LINK : warning LNK4098: defaultlib ‘MSVCRT’ conflicts with use of other libs; use /NODEFAULTLIB:library
    1>LINK : warning LNK4098: defaultlib ‘LIBCMT’ conflicts with use of other libs; use /NODEFAULTLIB:library
    1>glew32s.lib(glew.obj) : warning LNK4204: ‘C:Usersmichael.richardsDownloadsopengl-series-masterwindows1_project_skeletonDebugvc100.pdb’ is missing debugging information for referencing module; linking object as if no debug info
    1>  01_project_skeleton.vcxproj -> C:Usersmichael.richardsDownloadsopengl-series-masterwindows1_project_skeletonDebug1_project_skeleton.exe
    1>  C:Usersmichael.richardsDownloadsopengl-series-masterwindows1_project_skeletonsourcefragment-shader.txt
    1>  C:Usersmichael.richardsDownloadsopengl-series-masterwindows1_project_skeletonsourcevertex-shader.txt
    1>          2 file(s) copied.
    ========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

    It starts running but almost immediately crashes with the following message:

    Unhandled exception at 0x77a315de in 01_project_skeleton.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0035fc04..

    Just thought I’d give you a heads up.

  • http://www.tomdalling.com/ Tom Dalling

    What’s the exception message or stack trace? It might be your graphics drivers.

  • http://www.twitter.com/wolferey Håvard Stene Skjærvik

    I get the same thing, using VS2010 on Windows 7 64-Bit. I started debugging and found it threw the following exception error: “error c0000 syntax error unexpected $undefined at token undefined”, and the program itself showed the “ERROR: Compile failure in shader:”. *Since it obviously can’t compile the shader for some reason, I started stepping over the shader.cpp file, and I found that when it reads the file in the Shader::shaderFromFile() function, char* sourceCode gets some garbage text at the end:

    “#version 150in vec4 vert;void main() {    // does not alter the verticies at all    gl_Position = vert;}ÍÍÍÍÍÍÍ”

    My guess is it doesn’t read the null terminator at the end of the file properly on windows, and because of that you get some garage text that ruins the compilation of the shader and thus gives the above std::runtime_error.

  • http://www.tomdalling.com/ Tom Dalling

    Thanks for looking into that. I think I have fixed the problem: https://github.com/tomdalling/opengl-series/commit/d1aa366108da76891ff92f1479cb8bc573a4f94f

    I can’t reproduce the bug on my Windows 7 32bit installation, though, so it would be great if someone could confirm that it is working.

  • http://www.twitter.com/wolferey Håvard Stene Skjærvik

    Works for me now :)

  • http://www.tomdalling.com/ Tom Dalling

    Great. Thanks for testing.

  • http://www.thomasmuntaner.com/ Thomas Muntaner

    If anyone is using XCode with homebrew instead of macports, change the header search path to “/opt/local/include” and the library search path to “/usr/local/lib” in the project build settings.

  • Joe

    Running OS X 10.6.8, XCode 3.2.6. After installing glew and glm using MacPorts, this is the error I get when trying to build the project in XCode:

    CompileC build/article-01-skeleton.build/Debug/article-01-skeleton.build/Objects-normal/x86_64/main.o source/main.mm normal x86_64 objective-c++ com.apple.compilers.llvmgcc42
    cd /Users/Emonk/opengl-series/osx/01_project_skeleton
    setenv LANG en_US.US-ASCII
    /Developer/usr/bin/llvm-gcc-4.2 -x objective-c++ -arch x86_64 -fmessage-length=0 -pipe -Wno-trigraphs -fpascal-strings -fasm-blocks -O0 -Werror -pedantic -DDEBUG=1 -fvisibility-inlines-hidden -mmacosx-version-min=10.7 -gdwarf-2 -iquote /Users/Emonk/opengl-series/osx/01_project_skeleton/build/article-01-skeleton.build/Debug/article-01-skeleton.build/article-01-skeleton-generated-files.hmap -I/Users/Emonk/opengl-series/osx/01_project_skeleton/build/article-01-skeleton.build/Debug/article-01-skeleton.build/article-01-skeleton-own-target-headers.hmap -I/Users/Emonk/opengl-series/osx/01_project_skeleton/build/article-01-skeleton.build/Debug/article-01-skeleton.build/article-01-skeleton-all-target-headers.hmap -iquote /Users/Emonk/opengl-series/osx/01_project_skeleton/build/article-01-skeleton.build/Debug/article-01-skeleton.build/article-01-skeleton-project-headers.hmap -Wall -F/Users/Emonk/opengl-series/osx/01_project_skeleton/build/Debug -I/Users/Emonk/opengl-series/osx/01_project_skeleton/build/Debug/include -I/opt/local/include -I/Users/Emonk/opengl-series/osx/01_project_skeleton/thirdparty/glfw/include -I/Users/Emonk/opengl-series/osx/01_project_skeleton/build/article-01-skeleton.build/Debug/article-01-skeleton.build/DerivedSources/x86_64 -I/Users/Emonk/opengl-series/osx/01_project_skeleton/build/article-01-skeleton.build/Debug/article-01-skeleton.build/DerivedSources -c /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm -o /Users/Emonk/opengl-series/osx/01_project_skeleton/build/article-01-skeleton.build/Debug/article-01-skeleton.build/Objects-normal/x86_64/main.o

    In file included from /opt/local/include/glm/glm.hpp:89,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/core/setup.hpp:571:1: error: multi-line comment
    In file included from /opt/local/include/glm/./core/_detail.hpp:32,
                     from /opt/local/include/glm/glm.hpp:96,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/setup.hpp:571:1: error: multi-line comment
    In file included from /opt/local/include/glm/./core/type_float.hpp:33,
                     from /opt/local/include/glm/./core/type.hpp:33,
                     from /opt/local/include/glm/glm.hpp:97,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/setup.hpp:571:1: error: multi-line comment
    In file included from /opt/local/include/glm/./core/type_int.hpp:32,
                     from /opt/local/include/glm/./core/type.hpp:34,
                     from /opt/local/include/glm/glm.hpp:97,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/setup.hpp:571:1: error: multi-line comment
    In file included from /opt/local/include/glm/./core/func_exponential.inl:29,
                     from /opt/local/include/glm/./core/func_exponential.hpp:121,
                     from /opt/local/include/glm/glm.hpp:100,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:29:1: error: “VECTORIZE2_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_trigonometric.inl:29,
                     from /opt/local/include/glm/./core/func_trigonometric.hpp:199,
                     from /opt/local/include/glm/glm.hpp:99,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:29:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_exponential.inl:29,
                     from /opt/local/include/glm/./core/func_exponential.hpp:121,
                     from /opt/local/include/glm/glm.hpp:100,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:62:1: error: “VECTORIZE_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_trigonometric.inl:29,
                     from /opt/local/include/glm/./core/func_trigonometric.hpp:199,
                     from /opt/local/include/glm/glm.hpp:99,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:62:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_exponential.inl:29,
                     from /opt/local/include/glm/./core/func_exponential.hpp:121,
                     from /opt/local/include/glm/glm.hpp:100,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:114:1: error: “VECTORIZE2_VEC_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_trigonometric.inl:29,
                     from /opt/local/include/glm/./core/func_trigonometric.hpp:199,
                     from /opt/local/include/glm/glm.hpp:99,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:114:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_exponential.inl:29,
                     from /opt/local/include/glm/./core/func_exponential.hpp:121,
                     from /opt/local/include/glm/glm.hpp:100,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:156:1: error: “VECTORIZE_VEC_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_trigonometric.inl:29,
                     from /opt/local/include/glm/./core/func_trigonometric.hpp:199,
                     from /opt/local/include/glm/glm.hpp:99,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:156:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:29:1: error: “VECTORIZE2_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_exponential.inl:29,
                     from /opt/local/include/glm/./core/func_exponential.hpp:121,
                     from /opt/local/include/glm/glm.hpp:100,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:29:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:62:1: error: “VECTORIZE_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_exponential.inl:29,
                     from /opt/local/include/glm/./core/func_exponential.hpp:121,
                     from /opt/local/include/glm/glm.hpp:100,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:62:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:114:1: error: “VECTORIZE2_VEC_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_exponential.inl:29,
                     from /opt/local/include/glm/./core/func_exponential.hpp:121,
                     from /opt/local/include/glm/glm.hpp:100,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:114:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:156:1: error: “VECTORIZE_VEC_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_exponential.inl:29,
                     from /opt/local/include/glm/./core/func_exponential.hpp:121,
                     from /opt/local/include/glm/glm.hpp:100,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:156:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_geometric.inl:29,
                     from /opt/local/include/glm/./core/func_geometric.hpp:136,
                     from /opt/local/include/glm/glm.hpp:103,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:29:1: error: “VECTORIZE2_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:29:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_geometric.inl:29,
                     from /opt/local/include/glm/./core/func_geometric.hpp:136,
                     from /opt/local/include/glm/glm.hpp:103,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:62:1: error: “VECTORIZE_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:62:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_geometric.inl:29,
                     from /opt/local/include/glm/./core/func_geometric.hpp:136,
                     from /opt/local/include/glm/glm.hpp:103,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:67:1: error: “VECTORIZE2_VEC_SCA” redefined
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:67:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_geometric.inl:29,
                     from /opt/local/include/glm/./core/func_geometric.hpp:136,
                     from /opt/local/include/glm/glm.hpp:103,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:109:1: error: “VECTORIZE_VEC_SCA” redefined
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:109:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_geometric.inl:29,
                     from /opt/local/include/glm/./core/func_geometric.hpp:136,
                     from /opt/local/include/glm/glm.hpp:103,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:114:1: error: “VECTORIZE2_VEC_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:114:1: error: this is the location of the previous definition
    In file included from /opt/local/include/glm/./core/func_geometric.inl:29,
                     from /opt/local/include/glm/./core/func_geometric.hpp:136,
                     from /opt/local/include/glm/glm.hpp:103,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:156:1: error: “VECTORIZE_VEC_VEC” redefined
    In file included from /opt/local/include/glm/./core/func_common.inl:29,
                     from /opt/local/include/glm/./core/func_common.hpp:426,
                     from /opt/local/include/glm/glm.hpp:101,
                     from /Users/Emonk/opengl-series/osx/01_project_skeleton/source/main.mm:23:
    /opt/local/include/glm/./core/_vectorize.hpp:156:1: error: this is the location of the previous definition

  • http://www.tomdalling.com/ Tom Dalling

    For some reason (not sure why) GLM won’t compile with LLVM GCC, so you have to upgrade to Xcode 4 and use the “Apple LLVM compiler”.

  • Joe

    Sorry for the enormous post! Thanks for the speedy reply though. I was afraid it was going to be an XCode 3 issue. 

  • http://www.tomdalling.com/ Tom Dalling

    No problem.

  • Pingback: Game development (Day 7) « Ore no mirai

  • http://twitter.com/codecowboy Mr C. Cowboy Esq.

    This doesn’t sound quite right. I don’t use macports at all so dont have a /opt directory. I changed both paths to /usr/local/lib and the project builds but libGlew.a is highlighted in red in the project navigator.

  • Ion

    Great article. Works perfectly on Linux, however on OS X I can see a white background window for a fraction of second when the program starts, after this the background is black and the triangle white as expected. Same goes if I enable the resize for a window and resize the window …

    Any idea how to get rid of this artifact ?

    Thanks.

  • Ion

    Solved! You simply need to register a resize function, clear the screen and swap the buffers, when the window is resized. Apparently you need this function, on OS X, even when you explicitly disable the resize.

  • Luke

    I’ve run into a problem when running the supplied project on Windows 7
    64-bit. When I run it, a screen pops up, then immediately closes and
    exits. After stepping through, I found that the problem happens at
    glfwOpenWindow() in AppMain(). Here’s the stack trace:

    > 01_project_skeleton.exe!_ftol2_sse() Line 40 Asm
    01_project_skeleton.exe!AppMain() Line 129 + 0x1c bytes C++
    01_project_skeleton.exe!main(int argc, char * * argv) Line 166 + 0×5 bytes C++
    01_project_skeleton.exe!__tmainCRTStartup() Line 555 + 0×19 bytes C
    01_project_skeleton.exe!mainCRTStartup() Line 371 C
    kernel32.dll!765e33aa()
    [Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
    ntdll.dll!771b9ef2()
    ntdll.dll!771b9ec5()

    At this point, Visual Studio opens a tab saying there is no source code available. The output after running is this:

    ’01_project_skeleton.exe’:
    Loaded
    ‘C:UsersLukeDocumentsProgrammingopengl-series-masterwindows1_project_skeletonDebug1_project_skeleton.exe’,
    Symbols loaded.
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64ntdll.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64kernel32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64KernelBase.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64opengl32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64msvcrt.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64advapi32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64sechost.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64rpcrt4.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64sspicli.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64cryptbase.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64gdi32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64user32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64lpk.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64usp10.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64glu32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64ddraw.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64dciman32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64setupapi.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64cfgmgr32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64oleaut32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64ole32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64devobj.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64dwmapi.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64msvcp100d.dll’, Symbols loaded.
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64msvcr100d.dll’, Symbols loaded.
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64imm32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64msctf.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64uxtheme.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64winmm.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64clbcatq.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64atiglpxx.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64ig4icd32.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64atigktxx.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64version.dll’, Cannot find or open the PDB file
    ’01_project_skeleton.exe’: Loaded ‘C:WindowsSysWOW64aticfx32.dll’, Cannot find or open the PDB file
    First-chance
    exception at 0x75cac41f in 01_project_skeleton.exe: Microsoft C++
    exception: std::runtime_error at memory location 0x002efb94..
    ’01_project_skeleton.exe’: Unloaded ‘C:WindowsSysWOW64winmm.dll’
    The program ‘[6112] 01_project_skeleton.exe: Native’ has exited with code 0 (0×0).

    At
    first I thought that it was because of the way my laptop is. It has
    Intel integrated graphics, which supports only up to 3.1. Even though I
    also have a graphics card in my laptop that supports 3.2, I decided to
    lower the OpenGL version. At both 3.1 and 3.0, the only difference is
    that it exits withe the code 1 (0×1). I’m going to look around some more
    to see if I can figure out what’s going on, but I thought I would let
    you know in the mean time.

  • http://www.tomdalling.com/ Tom Dalling

    I can’t reproduce that crash, but it looks like it’s crashing when converting the screen size from floats to ints. Try replace this:

    glfwOpenWindow((int)SCREEN_SIZE.x, (int)SCREEN_SIZE.y, 8, 8, 8, 8, 0, 0, GLFW_WINDOW)

    with this:

    glfwOpenWindow(800, 600, 8, 8, 8, 8, 0, 0, GLFW_WINDOW)

    If that fixes it, let me know and I’ll fix the code on github.

  • Felipe

    Hi!
    I just wanted you know that this series about Modern OpenGL help me a lot! Thank you.

    In fact, i just had problems to initialize glfw. I needed to comment all hints except the NO_RESIZE one.

    My hardware is a IntelHD 3000.

    Thank you very much, i hope you continue with this series.

    Felipe

  • http://www.tomdalling.com/ Tom Dalling

    Hi Felipe,

    It might be because the IntelHD 3000 drivers only support OpenGL 3.1, and these articles use 3.2. I’m glad you got it working, thought.

  • http://twitter.com/Rimher Umberto Sonnino

    Hello there! I’m getting an error due to the glm::vec2 used in main.mm the error is at line 77 in the type_vec2.hpp file in the glm headers, because it says that “anonymous structs are a GNU extension”, thus i cannot build the project.

    Is there an alternative on how to make it work without that single header?

    Currently on Mountain Lion 10.8.3
    XCode 4.6.1

  • http://www.tomdalling.com/ Tom Dalling

    Hi Umberto,

    This is a problem with the latest version of GLM. I’ll fix it later today by adding an older version of GLM to the github repo.

    – Tom

  • http://twitter.com/Rimher Umberto Sonnino

    Wow that was really fast! Thank you very much =D
    Great tutorials btw

  • Mitchell Neville

    Great job, Tom. Thanks for OpenGL articles that are easy to set up as well as informative. Definitely the best I’ve seen.

  • Sebastian Szymak

    Looking for good tutorials about OpenGL I found this place. I have 10+ years of experience in commercial software development but I’m new to OpenGL. Your tutorials are really goo… great! Thanks! Well done!

  • Biotic Pixels

    I’m trying to set up a project in Xcode using the same libraries, getting them to work is a nightmare. This is glossed-over everywhere.
    Supposedly as simple as compile, install, #include, but with GLEW and GLFW all I get is ‘file not found’, and they exist in the correct directories in usr/. And then there’s the GLM instructions: ‘just include the header’… Great, I’m assuming these files need to go somewhere specific for that to work though, so any suggestions?

    I have no idea, really appreciate some help. Great tutorials by-the-way. Really easy to follow.

  • Biotic Pixels

    The nightmare continues. I’ve resorted to adapting the skeleton example provided, just updating the libraries.
    Any idea why the most recent GLM version (9.4.4 at this time) won’t allow the project to compile using C++11? (The error is ‘Anonymous structs are a GNU extension’)

  • http://www.tomdalling.com/ Tom Dalling

    I had to downgrade GLM to 0.9.3.4 because the latest version wouldn’t compile with Xcode, so you’re probably facing the same problem.

    As for adding libraries to a project in general, the two most important settings are the header and library search paths. I’ve included a screenshot, and you can look in any of the Xcode projects to see how they are set up.

  • Biotic Pixels

    If you are having the same problem I’ll downgrade. The latest version does compile using C++98, not sure it’s really worth it.

    Gathered how to add headers and libraries from studying your settings. The whole process of installing and adding them into the project is complete madness.
    Still curious about why it’s necessary for GLEW to add a reference to ‘glew.c’ to the project, not ‘libGLEW.a’, but it’s opposite for GLFW – being necessary to add a reference to ‘libglfw.a’. Nothing intuitive about that, so how did you know that needed to be done?

  • http://www.tomdalling.com/ Tom Dalling

    Well you usually link the binary (the “.a” file) into your project, but seeing as glew fits into a single file with minimal dependencies, you can just add that to the project and you don’t have to worry about the binary. GLFW is a more complicated project, so it’s easier to use precompiled binaries.

  • Nahuel Bergamo

    Some great and practical info on the topic for beginners like me :) keep it up!

  • Kyle Almryde

    Tom, I can not thank you enough for taking the (considerable) time to put this amazing tutorial together. Truly, you are a godsend! Thank you for everything you do!

  • Matthias

    Finally a tutorial that introduces all the functions in structured and easily understandable way.
    I’ve had no contact to 3D programming at all until now. All other tutorials basically assume you already understand how the whole pipeline works and needs to be set up. This really helps in getting started!

    Exactly what I was looking for the wohle week!

    Thanks a lot! Thumbs up!

  • Lee

    Great article! In my country, South Korea, there are few articles about modern openGL. It is great helpful for me to learn openGL. Thanks a lot.

  • Khantil Patel

    Tom, Thanks very much… I was looking all over the google for such an focused and well explained tutorial to start with modern OpenGL. Thanks again!!.

  • NULL

    Some linux distributions are now shipping with glfw3 which is incompatible with glfw2, luckily they don’t conflict. After installing glfw2 the makefiles needed to be updated:
    find -name “*.make” | xargs sed -i ‘s/lglfw/lglfw2/’

  • ZipZapMAc

    Really great tutorial! I think it would be awesome, if you could add tutorial on how to setup all that stuff without using glfw on OS X.

  • Ning

    Great tutorial,tom.
    One question is,why the glBindVertexArray is used to bind/unbind so many times, can we just bind it first and unbound it after we draw?

    Thanks

  • http://www.tomdalling.com/ Tom Dalling

    In this article, the VAO is only bound once when it is created, and then once per frame drawn. That’s pretty much the bare minimum number of bindings. Which call to glBindVertexArray are you asking about removing?

  • Ning

    Thanks for replying, i mean the glBindVertexArray(0); in the last statement of LoadTriangle function

  • http://www.tomdalling.com/ Tom Dalling

    Well, since there is only one VAO in this article, you don’t have to ever unbind it in this particular case. But, if you’re using one VAO per 3D asset, which will happen in later articles, then they need to be unbound every time you create or draw a different 3D asset.

    The main reason to unbind everything after use is because OpenGL has a lot of global state, and that makes it easy to introduce bugs. If you unbind and reset all the global state after every time you use it, it’s easier to avoid those bugs. I doubt that it would cause serious performance problems, but if it does, it’s pretty easy to optimise binding and unbinding later.

  • Jeff

    Hi Tom, great tutorial series. For anyone who wants a good video over-view of this (a companion video almost) there’s a brand new 3 hour tutorial on YouTube here http://www.youtube.com/watch?v=T8gjVbn8VBk which covers the same material in a similar order, it really helped me put a lot of it into context

    I’m now following through Tom’s tutorials with a much better understanding of what I’m doing!

  • http://www.tomdalling.com/ Tom Dalling

    Holy moly, that’s a big video! Good find.

  • Peter

    Hey Tom, I want to ask you, is there a way to render something (again using GLFW) and hold the window open without looping through “while (glfwGetWindowParam(GLFW_OPENED))”. My idea is to render the scene just once, not in real time. Something like that:

    // do some stuff
    glDrawPixels(…);
    glfwSwapBuffers();
    // wait until user closes the window

  • http://www.tomdalling.com/ Tom Dalling

    Yep, you normally use `glfwWaitEvents` when you don’t want to render at max speed, because it puts the thread to sleep until the user does something. Then, you can take the `Render` call out of the main loop, and just call it once before the main loop starts. Something like this:

    Render();
    while(glfwGetWindowParam(GLFW_OPENED)){
    glfwWaitEvents();
    }

    You could also call `Render` on a certain event, like when the user presses the space key.

  • Peter

    Thanks, that worked as I needed !

  • Ray Garner

    what version of glfw are you using here?

  • http://www.tomdalling.com/ Tom Dalling