1. OpenGL 4 Window
Introduction
OpenGL has undergone some major changes recently from version 3 and onwards. OpenGL 3 introduced a new way of programming in OpenGL that slightly raises the learning curve, but also does away with the entire Immediate Mode by deprecating a lot of the functions. Now I know I have called this part of the site “OpenGL 4 Tutorials”, and all of a sudden I am talking about OpenGL 3, this is because OpenGL 3 and OpenGL 4 are extremely similar, with OpenGL 4 bringing in some new extensions, and because my graphics card only supports OpenGL 3.x. If you would like to see some OpenGL 4 extensions in use, you can always donate and help me get a new graphics card. In this tutorial, I am going to be simply creating a window with an OpenGL 3.2 context attached, nothing more, nothing less. These tutorials are going to be for Windows only, but if you are keen to get them working on a different OS (My Macbook doesn’t support OpenGL 3.x), please send me the ports and I will post them up.
OpenGL 3+ Key Differences
An OpenGL 3+ and 4 context requires you to create a standard OpenGL context (version 1.x or 2.x) and then get your application to opt-in to using an OpenGL 4 context.
Without the Immediate Mode, OpenGL has gone for an almost entirely shader driven architecture, which gives us control over everything from the word go, and also greatly improves performance.
When it comes to rendering shapes, instead of setting the state and then calling the vertices one by one, OpenGL 3 and upwards wants us to use Vertex Buffer Objects and Vertex Buffer Arrays straight out. Vertex Buffer Objects were available in OpenGL 1.5 and up as an extension, but they are now a part of the core of OpenGL.
Matrices are one of the major things affected by OpenGL 3. To put it simply, OpenGL does no matrix operations for us such as setting the Projection Matrix, setting the Model Matrix and setting the View Matrix. This means calls such as glRotate and glTranslate are now deprecated and not recommended. OpenGL now likes us to handle our own matrices. I will talk about this in a later tutorial, but there is a library called GLM, designed for use with OpenGL and GLSL, which will help us with our matrix operations.
OpenGL has undergone some major changes recently from version 3 onwards. This program has access to the possibility of studying generic viagra 50 mg medicine per man. If you want to read more about this, follow this link.
Coding
*note* You can jump straight to the bottom of this page to grab the PDF version of this tutorial, or the project files. *note*
Let’s finally get into this tutorial, because it is going to be a long one. I’m also going to be aiming for a more Object Oriented approach to programming in these newer tutorials.
This tutorial is going to be very similar in some ways to most Win32 OpenGL tutorials available, the only difference being that it has an OpenGL 3.2 context instead of a standard context. So open up Visual Studio and create a new Windows Console Application in C++. Make sure it is empty to begin with, and then create 4 files. I am calling them: “main.cpp, main.h, opengl_3.cpp, opengl_3.h”. I am going to go through these files one by one, starting with the header files, so that we don’t get mixed up shuffling between them.
Main.h
Main.h is going to contain all of our header files for the time being. So open it up and paste the following code. I won’t explain it, as it is pretty straight forward; we are including some header files and linking some libraries, the only tricky part may be “#pragma once”, which isn’t standard but is widely supported, and means to only include the file once during compilation.
#pragma once // Include Windows functions #include // Include input and output operations #include // OpenGL and GLEW Header Files and Libraries #include #include #pragma comment(lib, "glew32.lib") #pragma comment(lib, "opengl32.lib")
As you can see from the above code, we are once again using GLEW. GLEW is up to date with the latest OpenGL 3.x and possibly 4.0 extensions. I highly recommend the use of it as it makes coding in OpenGL so much easier without having to worry about declaring extensions by yourself.
Opengl_3.h
The first thing we want to include here is our main.h file. So add the line:
#include "main.h"
Once we have included our main header file which contains access to the GLEW and OpenGL commands, we are going to want to create a new class. I am going to call this class OpenGLContext and it is going to be responsible for creating a context, handling setting up of our scene, resizing of our scene, rendering of our scene, and finally, cleaning up of our scene. Start off with an empty class like so:
/** OpenGLContext is a class designed to store all of your OpenGL functions and keep them out of the way of your application logic. Here we have the ability to create an OpenGL context on a given window and then render to that window. */ class OpenGLContext { public: private: protected: };
Next up, we are going to come up with some protected variables that will keep track of our window. When working with the Win32 API, each Window you see has its own HWND which is the identifier for that window. We also have two different contexts we need to work with, the first is the HDC, which is the device context, and the second is the HGLRC which is an OpenGL rendering context. If we create a variable to handle each of these, we get:
class OpenGLContext { ... protected: HGLRC hrc; // Rendering context HDC hdc; // Device context HWND hwnd; // Window identifier };
Once we have the information we need for a window and a context, we need to keep track of the width and the height of our window. If we don’t keep track of these, then whenever we resize the window, we will find that parts of it are not rendered to, or we render more than we have to, resulting in some of our image being cut off. We are going to add two private variables to keep track of this for us:
class OpenGLContext { ... private: int windowWidth; // Store the width of our window int windowHeight; // Store the height of our window ... };
Finally we need to come up with some method stubs for controlling our OpenGLContext object. I am going to work with two different constructors and a destructor for some standard methods. Followed by four other methods for working with our context which are going to be called “create30Context(HWND), setupScene(void), reshapeWindow(int, int), renderScene(void)”.
class OpenGLContext { public: OpenGLContext(void); // Default constructor OpenGLContext(HWND hwnd); // Constructor for creating our context given a hwnd ~OpenGLContext(void); // Destructor for cleaning up our application bool create30Context(HWND hwnd); // Creation of our OpenGL 3.x context void setupScene(void); // All scene information can be setup here void reshapeWindow(int w, int h); // Method to get our window width and height on resize void renderScene(void); // Render scene (display method from previous OpenGL tutorials) ... };
This is all we are going to need for our opengl_3.h header file for now. So let’s go and start on opengl_3.cpp.
Opengl_3.cpp
To give use access to our class methods, you are going to want to include opengl_3.h of course, so that will be line number one for this file.
#include "opengl_3.h"
Now let’s get to building us some methods for our class. I am going to start off with the two constructors and the destructor. Our first constructor, the default one, at the moment does nothing, so you can just create an empty constructor. But the second one will make a call to our create30Context method.
/** Default constructor for the OpenGLContext class. At this stage it does nothing but you can put anything you want here. */ OpenGLContext::OpenGLContext(void) { } /** Constructor for the OpenGLContext class which will create a context given a windows HWND. */ OpenGLContext::OpenGLContext(HWND hwnd) { create30Context(hwnd); // Create a context given a HWND }
When we get to our destructor, it will handle the removal of our rendering context and our device context. For this, we make use of wglMakeCurrent, wglDeleteContext and ReleaseDC.
/** Destructor for our OpenGLContext class which will clean up our rendering context and release the device context from the current window. */ OpenGLContext::~OpenGLContext(void) { wglMakeCurrent(hdc, 0); // Remove the rendering context from our device context wglDeleteContext(hrc); // Delete our rendering context ReleaseDC(hwnd, hdc); // Release the device context from our window }
Let’s get onto our create30Context method now. This method will take in a HWND value to identify a window, and will create a valid rendering and device context on top of it. Create an empty method for this, and then we will set the HWND for our object, and get a valid HDC. I’ve made this method a Boolean value, so we can return a false value if we are unable to successfully create a context of any kind. However by default, we will fall back to and OpenGL 2.1 context if unable to create an OpenGL 3.x context.
/** create30Context creates an OpenGL context and attaches it to the window provided by the HWND. This method currently creates an OpenGL 3.2 context by default, but will default to an OpenGL 2.1 capable context if the OpenGL 3.2 context cannot be created. */ bool OpenGLContext::create30Context(HWND hwnd) { this->hwnd = hwnd; // Set the HWND for our window hdc = GetDC(hwnd); // Get the device context for our window return true; // We have successfully created a context, return true }
The next thing we need to do, is create a variable called a PIXELFORMATDESCRIPTOR which determines how many bits of colour and depth we get, along with giving us double buffering and support for OpenGL. To do this, we first need to create a new variable, I am going to call it pfd and then we need to allocate some empty memory for it. Here, 32 bits of colour, gives us R, G, B and A channels, while 24 bits gives us only R, G and B (each channel takes 8 bits). After we have set aside some memory for this variable, we need to set the size of it, which will always be sizeof(PIXELFORMATDESCRIPTOR). Next, we will set the flags which allow double buffering, opengl support and drawing to a window. Next up, we set the iPixelType to allow RGBA pixels, before we set how many bits we want in our color and depth buffers. Finally, we need to set the iLayerType. We are going to set this to the Main_Plane for our window.
bool OpenGLContext::create30Context(HWND hwnd) { this->hwnd = hwnd; // Set the HWND for our window hdc = GetDC(hwnd); // Get the device context for our window PIXELFORMATDESCRIPTOR pfd; // Create a new PIXELFORMATDESCRIPTOR (PFD) memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); // Clear our PFD pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); // Set the size of the PFD to the size of the class pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; // Enable double buffering, opengl support and drawing to a window pfd.iPixelType = PFD_TYPE_RGBA; // Set our application to use RGBA pixels pfd.cColorBits = 32; // Give us 32 bits of color information (the higher, the more colors) pfd.cDepthBits = 32; // Give us 32 bits of depth information (the higher, the more depth levels) pfd.iLayerType = PFD_MAIN_PLANE; // Set the layer of the PFD return true; // We have successfully created a context, return true }
Next up, we need to choose a pixel format for our device context, based on our pixel format descriptor. To do this, we make a call to ChoosePixelFormat and pass through our hdc and pfd variables, in return we get an integer value that represents our pixel format, which we can then use to set our pixel format for our device context using SetPixelFormat as seen below.
bool OpenGLContext::create30Context(HWND hwnd) { this->hwnd = hwnd; // Set the HWND for our window hdc = GetDC(hwnd); // Get the device context for our window ... int nPixelFormat = ChoosePixelFormat(hdc, &pfd); // Check if our PFD is valid and get a pixel format back if (nPixelFormat == 0) // If it fails return false; bool bResult = SetPixelFormat(hdc, nPixelFormat, &pfd); // Try and set the pixel format based on our PFD if (!bResult) // If it fails return false; return true; // We have successfully created a context, return true }
Once we have our pixel format all set up. We need to go ahead and create our OpenGL context. To do this, we need to first create an OpenGL 2.1 compatible context, and then call a new OpenGL 3.x extension called wglCreateContextAttribsARB to create an OpenGL 3.x compatible context. So let’s create our OpenGL 2.1 context as per a standard Win32 OpenGL application.
HGLRC tempOpenGLContext = wglCreateContext(hdc); // Create an OpenGL 2.1 context for our device context wglMakeCurrent(hdc, tempOpenGLContext); // Make the OpenGL 2.1 context current and active And now we will go ahead and enable GLEW so that we can use our new OpenGL 3.x context creation extension.
GLenum error = glewInit(); // Enable GLEW if (error != GLEW_OK) // If GLEW fails return false;
To create our context correctly, we need to set some attributes. These include the major and minor version of the OpenGL version we wish to use, followed by a flag to set this as a forward compatible context. When I say major and minor version, OpenGL versions come in this naming convention “major.minor”, so in OpenGL 3.2, the major version is 3 and the minor version is 2. This can be change to give OpenGL 3.2, 3.1, 3.0 or even 4.0 contexts.
int attributes[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, // Set the MAJOR version of OpenGL to 3 WGL_CONTEXT_MINOR_VERSION_ARB, 2, // Set the MINOR version of OpenGL to 2 WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, // Set our OpenGL context to be forward compatible 0 };
Now that our attributes are all sorted out, we are going to do a check to see if our OpenGL 3.x context creation extension is available. If it is, we are going to create our OpenGL 3.2 context, if it isn’t, then we are going to stick with the OpenGL 2.1 context we created above. To switch to the new context after it has been created, we need to make sure that no context is current on our window, and then delete the old context, before finally making our new OpenGl 3.2 context current.
if (wglewIsSupported("WGL_ARB_create_context") == 1) { // If the OpenGL 3.x context creation extension is available hrc = wglCreateContextAttribsARB(hdc, NULL, attributes); // Create and OpenGL 3.x context based on the given attributes wglMakeCurrent(NULL, NULL); // Remove the temporary context from being active wglDeleteContext(tempOpenGLContext); // Delete the temporary OpenGL 2.1 context wglMakeCurrent(hdc, hrc); // Make our OpenGL 3.0 context current } else { hrc = tempOpenGLContext; // If we didn't have support for OpenGL 3.x and up, use the OpenGL 2.1 context }
Finally, to check that we have created our context correctly, we are just going to pull out the MAJOR and MINOR version numbers for OpenGL and output them to a console.
int glVersion[2] = {-1, -1}; // Set some default values for the version glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]); // Get back the OpenGL MAJOR version we are using glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]); // Get back the OpenGL MAJOR version we are using std::cout << "Using OpenGL: " << glVersion[0] << "." << glVersion[1] << std::endl; // Output which version of OpenGL we are using On Windows, you won’t get a console for a Win32 Application, but a nifty trick to get console output, is to open up Command Prompt, navigate to your directory with your executable file, and use something like: “program.exe > temp.txt”
This will run your application, and save all output to the file temp.txt. Linux programmers may already be familiar with calls like this.
Now we still have three more methods we need to create here before we are done, but luckily for us, they are extremely short. The first I will look at is setupScene, which takes no parameters, and will only set up our OpenGL Clear Color value. I am going to set it to the nice CornFlowerBlue you get when working with XNA. I grew fond of this colour, and it looks nicer than a standard black or white.
/** setupScene will contain anything we need to setup before we render */ void OpenGLContext::setupScene(void) { glClearColor(0.4f, 0.6f, 0.9f, 0.0f); // Set the clear color based on Microsofts CornflowerBlue (default in XNA) }
Moving on, we now have our reshapeWindow method. This method will take in two integers, one for the width of our window and the other for the height of our window. It will then set our OpenGLContext objects width and height to these values.
/** reshapeWindow is called every time our window is resized, and it sets our windowWidth and windowHeight so that we can set our viewport size. */ void OpenGLContext::reshapeWindow(int w, int h) { windowWidth = w; // Set the window width windowHeight = h; // Set the window height }
And the last method for this file, is our renderScene method, which once again takes no arguments. The first thing we need to do, is set the size of our viewport to the size of our window, which is done with a call to glViewport. Next we will clear our color, depth and stencil buffers, before finally swapping our front and back buffers to draw to the screen.
/** renderScene will contain all our rendering code. The first thing we are going to do is set our viewport size to fill the entire window. Next up we are going to clear our COLOR, DEPTH and STENCIL buffers to avoid overlapping of renders. Any of your other rendering code will go here. Finally we are going to swap buffers. */ void OpenGLContext::renderScene(void) { glViewport(0, 0, windowWidth, windowHeight); // Set the viewport size to fill the window glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clear required buffers SwapBuffers(hdc); // Swap buffers so we can see our rendering }
Now we have everything in place for our basic OpenGL 3.2 context, so let’s go and finish off this tutorial with the main.cpp file, which will handle all of our Window creation.
Main.cpp
For the purpose of these tutorials, I am going to assume that we are working with single window applications and am not going to go for a more OO approach to window creation. So let’s get on to creating our window.
The first thing we need to do here is to include our common header files, main.h and opengl_3.h. Followed by declaring some variables. We are going to need an instance of an OpenGLContext object, a boolean value to say as to whether or not we are still running our application and a standard HINSTANCE variable for Win32. We are also going to give a method declaration for WndProc which is also required for a Windows application.
#include "main.h" #include "opengl_3.h" OpenGLContext openglContext; // Our OpenGL Context class bool running = true; // Whether or not the application is currently running HINSTANCE hInstance; // The HINSTANCE of this application LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Standard window callback
The rest of this tutorial, is made up of three methods. The first one here, is required in any Windows application and is responsible for our windows callbacks. We are going to look for calls to resize the window, and for calls to destroy the window. When we find a call to resize the window, we are going to call our openglContext.reshapeWindow method. Lets take a look at the definition for this method.
/** WndProc is a standard method used in Win32 programming for handling Window messages. Here we handle our window resizing and tell our OpenGLContext the new window size. */ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hWnd, message, wParam, lParam); }
In order to look for different window calls, we turn to the message parameter in the method definition. This is a UINT variable, which can be tied to any of the WM_* variables. We are going to need WM_SIZE for window resizing, and WM_DESTROY for calls to destroy the window. I am going to use a simple switch statement to check for these like so:
switch (message) { case WM_SIZE: // If our window is resizing { } case WM_DESTROY: { } }
When it comes to our window resizing, we are going to need to update our OpenGL context so that it knows the new size of the window. To do this, we can pull out the width and height of the window using calls to LOWORD(lParam) and HIWORD(lParam), which makes things fairly simple for us. Our method now becomes:
/** WndProc is a standard method used in Win32 programming for handling Window messages. Here we handle our window resizing and tell our OpenGLContext the new window size. */ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_SIZE: // If our window is resizing { openglContext.reshapeWindow(LOWORD(lParam), HIWORD(lParam)); // Send the new window size to our OpenGLContext break; } case WM_DESTROY: { } } return DefWindowProc(hWnd, message, wParam, lParam); }
The only thing left to check for now, is when a window is destroyed. Then we need to send a call to PostQuitMessage so that we can exit our application.
/** WndProc is a standard method used in Win32 programming for handling Window messages. Here we handle our window resizing and tell our OpenGLContext the new window size. */ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_SIZE: // If our window is resizing { openglContext.reshapeWindow(LOWORD(lParam), HIWORD(lParam)); // Send the new window size to our OpenGLContext break; } case WM_DESTROY: { PostQuitMessage(0); break; } } return DefWindowProc(hWnd, message, wParam, lParam); }
While we now have a method which will handle all of the call backs for our window, we need to actually go ahead and create a window. So I am going to create a new method called createWindow, which will return a boolean value which determines whether or not the window was created successfully. It’s parameters are an LPCWSTR for the title of the window, and two integers, one for the width and one for the height of the window.
bool createWindow(LPCWSTR title, int width, int height) { return true; }
Once we have our method skeleton in place, we need to setup some variables for our window. We will need a WNDCLASS, HWND and a DWORD. The WNDCLASS, which I will call windowClass sets all the basic information for a window, such as the icon, cursor, type of redraw, the instance of the owner application, etc. The HWND variable which I will just call hwnd, will hold the unique identifier for the window which we create, and finally the DWORD variable, which I am going to call dwExStyle and that just sets the type of window and that it has an edge.
I’m not going to go into detail about all the settings for this, as it’s not an OpenGL topic, its a Win32 topic, so here’s just the code. I have included a quick error check to make sure the windowClass variable can be registered:
bool createWindow(LPCWSTR title, int width, int height) { WNDCLASS windowClass; HWND hWnd; DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; hInstance = GetModuleHandle(NULL); windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; windowClass.lpfnWndProc = (WNDPROC) WndProc; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = hInstance; windowClass.hIcon = LoadIcon(NULL, IDI_WINLOGO); windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); windowClass.hbrBackground = NULL; windowClass.lpszMenuName = NULL; windowClass.lpszClassName = title; if (!RegisterClass(&windowClass)) { return false; } return true; }
Next up, we are going to create our window using the above window class, and then we are going to create our OpenGL context on the window before showing the window and making a quick call to update it.
bool createWindow(LPCWSTR title, int width, int height) { ... hWnd = CreateWindowEx(dwExStyle, title, title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, width, height, NULL, NULL, hInstance, NULL); openglContext.create30Context(hWnd); // Create our OpenGL context on the given window we just created ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); return true; }
This should now give us a window, with an OpenGL 3 context, and it should also be visible. The last thing we need to do is create a WinMain method which will be used to launch our application. Lets create an empty WinMain method, and then we will go ahead and fill this in. Note that I have left in the MSG variable called msg, just because we use it for our return value.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; return (int) msg.wParam; }
Before we fill this in, I am going to give a brief rundown of what to expect. The first few lines are going to be used to convert the title of the window from a char array to an LPCWSTR, they are just an annoying necessity because the CreateWindowEx method doesn’t support char arrays. The next two lines after this will create our window, and setup our OpenGL context, and we will end with a loop that will continue running for as long as the application does, and will be responsible for rendering and checking for window messages. Lets take a look at the first few lines, which convert our char array.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; /** The following 6 lines of code do conversion between char arrays and LPCWSTR variables which are used in the Windows API. */ char *orig = "OpenGL 3 Project"; // Our windows title size_t origsize = strlen(orig) + 1; const size_t newsize = 100; size_t convertedChars = 0; wchar_t wcstring[newsize]; mbstowcs_s(&convertedChars, wcstring, origsize, orig, _TRUNCATE); return (int) msg.wParam; }
Now let’s make the calls to create our window and setup our OpenGL scene.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { ... createWindow(wcstring, 500, 500); // Create our OpenGL window openglContext.setupScene(); // Setup our OpenGL scene return (int) msg.wParam; }
And finally we can set up our infinite loop. We will use the Win32 call to PeekMessage to check for calls to our window. If we get a WM_QUIT message we are going to set our running variable to false. Otherwise we are going to translate and dispatch the message, which is done in our callback. And if we don’t have any messages to process, we are going to call our openglContext.renderScene method before returning.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { ... /** This is our main loop, it continues for as long as running is true */ while (running) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // If we have a message to process, process it if (msg.message == WM_QUIT) { running = false; // Set running to false if we have a message to quit } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { // If we don't have a message to process openglContext.renderScene(); // Render our scene (which also handles swapping of buffers) } } return (int) msg.wParam; }
And wow, if you made it this far, give yourself a well deserved pat on the back! It took me a few days to write this tutorial, which is an initial setup on top of which all our other tutorials will build, so once you get it down you are ready to move onto the next. I am also providing Visual Studio 2010 projects for these tutorials, and PDF versions for download. For those of you who have been waiting, I’m sorry it has taken so long, but this is now a 13 page, 4,500+ word introduction to setting up an OpenGL compatible context on a window.
Downloads
Visual Studio 2010 Project
PDF version
If you have any questions you can comment below or email me at swiftless@gmail.com
I think we can assume that the hrc is always the current rendering context of the calling thread when the Dtor is called (why not?). In this case, we can let wglDeleteContext do the work of removing current rendering context. I think wglDeleteContext has this functionality according to https://docs.microsoft.com/en-us/windows/desktop/OpenGL/rendering-context-functions. One thing we need to modify is to move ReleaseDC(hwnd, hdc); to the line before wglDeleteContext(hrc);, which is required even if we remove the current rendering context of the calling thread manually, according to the aforementioned documentation. Do you think so?
For the value of cColorBits field of PIXELFORMATDESCRIPTOR when calling ChoosePixelFormat (line 44 of opengl_3.cpp), the documentation of PIXELFORMATDESCRIPTOR structure (https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-tagpixelformatdescriptor) says: “For RGBA pixel types, it is the size of the color buffer, excluding the alpha bitplanes.” Since alpha bitplanes are excluded, only RGB components should be counted towards cColorBits field. So this field should be filled with 3*8=24. Do you think so?
Hello !
Thank for this tutorial, it really help me !
I follow it with mingw and codeblocks, i had to change little thinks but now it work !
The visual studio project file seems to be corrupt, or maybe it has wrong MIME settings on your web server. If I try and unzip it, it says it is not a zip file
Hi, thanks for the excellent material for beginners.
BTW, is there any reason for using PeekMessage() instead of GetMessage() in the main loop?
I found out the same way of message pumping in SB6 sample code (win32raw) as well but, IMHO, it could make unwanted side effect in handling WM_CLOSE because of unpredictable behavior of PeekMessage(). For instance, it does not actually remove WM_PAINT message from the queue even if we specify PM_REMOVE as its last argument, which, in turn, can cause delays in message delivering/handling.
PeekMessage() in an infinite loop sometimes can block the user from quitting the program normally and also can leave the process in the memory just closing the GUI window only.
One more thing about performance is it makes the application repeatedly call the rendering function whenever the system lets the application look up its message queue but most of time it doesn’t have to repaint its window at all. If we use PeekMessage with a view to making some animation rendering run smoothly, I’d like to recommend the other way of direct control over timing sequence of animation; say using WM_TIMER message or so.
If you are somewhat familiar with using any debugging tools with Visual Studio, try to print out a sort of debugging message inside the rendering function then you can easily find out what I’m talking about.
If there is no specific reason for using PeekMessage, I’d like to suggest the following de facto standard message delivering & handling method after Charles Petzold’s;
In the main loop:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
The GetMessage() returns 0 only with WM_QUIT message, so we don’t have to deal with that message inside the main loop.
In the window procedure:
switch (msg)
{
case WM_SIZE:
openglContext.reshapeWindow(LOWORD(lParam), HIWORD(lParam));
break;
case WM_PAINT:
openglContext.renderScene();
break;
Hey, this works without flaw with MSVC 2010
No one should have any problems with this.
Thanks, It’s right on !
Great article, this has been EXTREMELY useful so far in my work on getting my SharpGL library up to date with modern OpenGL features, moving away from immediate mode. Once the next release is done I’ll mention this blog in the release notes – your broken down descriptions of how to do ‘modern’ OpenGL are great, much clearer than a lot of the official documentation.
I have this error here :
“error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup”
#include "main.h"
#include "opengl_3.h"
OpenGLContext openglContext;
bool running = true;
HINSTANCE hInstance;
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_SIZE:
{
openglContext.reshapeWindow(LOWORD(lParam),HIWORD(lParam));
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hWnd, message,wParam,lParam);
}
bool createWindow(LPCWSTR title,int width, int height)
{
WNDCLASS windowClass;
HWND hWnd;
DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
hInstance = GetModuleHandle(NULL);
windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
windowClass.lpfnWndProc = (WNDPROC) WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = NULL;
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = title;
if(!RegisterClass(&windowClass))
{
return false;
}
hWnd = CreateWindowEx(dwExStyle,title,title,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,0,width,height,NULL,NULL,hInstance,NULL);
openglContext.create30Context(hWnd);
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
return true;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE HPrevInstance, LPSTR lpdCmdLine, int nCmdShow)
{
MSG msg;
char *orig = "OpenGl 3 Project";
size_t origsize = strlen(orig) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars,wcstring,origsize,orig,_TRUNCATE);
createWindow(wcstring,500,500);
openglContext.setupScene();
while(running)
{
if(PeekMessage(&msg,NULL, 0,0,PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
running = false;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
openglContext.renderScene();
}
}
return (int) msg.wParam;
}
Nevermind. I was running it in a win32 console app not a project.
I came from programming graphics in unity through shader labs. I thought that getting help on that was difficult, but starting in opengl outside of a game engine, now that is insane. I spent all of yesterday just looking for a tutorial that actually used opengl 4, until I stumbled on this one.
Thank you for making this.
That being said, I still had alot of trouble, because I am going from an expert in C# (enough to competently use delegates, interfaces, ect) to a total newb in C++. I downloaded visual studio 2012 express, ( I would suggest sticking with 2010) and started this. THere are a few things I would like to tell my past self about this tutorial if I could, maybe it could be revised.
This tutorial uses GLEW, just GLEW. Set up your enviroment for GLEW and ONLY GLEW.
Try this page http://glew.sourceforge.net/install.html
Make this a windows application, NOT a CONSOLE application.
The “#includes” in main.h are , , and .
The system did not find my DLL, so open Properties by right clicking on the solutions name, select Debugging under Configuration Properties and set Enviroment to “Path=(Insert project directory here);%PATH%
As a total newb to DLL’s and C++ in general, these were not obvious. This is no offense to you, Swiftless, as this is the first opengl 4 tutorial that actually worked. I already have some good knowledge of the concepts of opengl and programming in general, but DLLs and links are killing me.
Again, thank you for this tutorial. Now, if only I could have a crossplatform windowing API for opengl 4, would make developing for progect logan much easier.
Oh, I did not notice this was HTML aware.
I meant to say
The “#includes” in main.h are <Windows.h>, <dInput.h>, <GL/glew.h> and <GL/wglew.h>.
I’m getting this error:
warning C4800: ‘BOOL’ : forcing value to bool ‘true’ or ‘false’ (performance warning)
for this code:
bool bResult = SetPixelFormat(hdc, nPixelFormat, &pfd);
if (!bResult) // If it fails
return false;
I’m far from being competent in openGL as I started on directX and moved over when I realized openGL was cross platform. What am I looking for here, why is it triggering?
Hi Paulus,
To me, this does not look like an OpenGL problem. the function SetPixelFormat() uses “BOOL” as a return type, where you specified “bool”.
The capital-letter BOOL is defined by system header files and probably defaults to int. Modern compilers may warn you about a hidden type-cast to a “smaller” type. The problem can probably be fixed by changing the line to:
BOOL bResult = SetPixelFormat(hdc, nPixelFormat, &pfd);
Congratulations!This tutorial helped me alot.
I’m confused about the extensions. How can I have a better understanding of them?
nice tutorial …
please anyone could tell me if there is a way to program glutfullscreen or GameMode (glutEnterGameMode) to run on my second screen?
thanks
Hi,
i have one correction for this tutorial. Don’t release a device context from a window with
the CS_OWNDC class style.
As described by Raymond in his blog “The Old New Thing”:
If you register a window class and include the CS_OWNDC flag in the class styles, then the window manager creates a DC for the window and puts it into the DC cache with a special tag that means “Do not purge this DC from the DC cache because it’s the CS_OWNDC for this window.” If you call BeginPaint or GetDC to get a DC for a CS_OWNDC window, then that DC will always be found and returned (since it was marked as “never purge”). The consequences of this are good, bad, and worse.
More info: http://blogs.msdn.com/b/oldnewthing/archive/2006/06/01/612970.aspx
Also why not use glViewport() correction inside the reshapeWindow() method?
Another thing:
Why do you use wglMakeCurrent(hdc, 0); in the destructor?
Is there any reason not to use wglMakeCurrent(NULL, NULL); as with the fake context created in the create30Context()?
Yet another thing, actually a question which led me here:
I currently only call wglCreateContext() to create my OpenGL context. Although, i don’t use the newer ARB function to create a context above major version 2, glGetString() returns a version above:
fprintf(stdout, “%s\n”, glGetString(GL_VENDOR));
fprintf(stdout, “%s\n”, glGetString(GL_RENDERER));
fprintf(stdout, “OpenGL %s\n”, glGetString(GL_VERSION));
Output on my old GeForce GTX 260:
NVIDIA Corporation
GeForce GTX 260/PCIe/SSE2
OpenGL 3.3.0
Output on my new GeForce GTX 660 Ti:
NVIDIA Corporation
GeForce GTX 660 Ti/PCIe/SSE2
OpenGL 4.3.0
Do you have a clue why this is?
Hey.
To those who asked about FreeGLUT.
FreeGLUT is perfectly compatible with GL4, and (unlike old GLUT) has some functions that make it okay for use in larger applications (mouse wheel functionality, ability to enter and make it leave the main loop, etc.).
As to the OS specific thing. You can use FreeGLUT, GLFW or SDL for a game or something similar. Amnesia The Dark Descent for example uses SDL for window functioning and input and it works fine on Windows and other platforms.
Besides GLEW, there’s also a really cool library called GLee which makes loading GL functions a breeze.
Hey Swiftless, not sure what’s happening…
“SetPixelFormat” is always returning false, and therefore the window is not popping up . Other implementations of OpenGL that I have done never had this problem. I’m only getting this problem from the implementation above.
If you know anything about this, help is greatly appreciated.
Thanks,
Nick
Hi Swiftless,
I am able to open the window,but I cannot visualize either the color or the square as the output.What is the error?I am compiling your code using VS2010 and OpenGL4.0
Hi Swiftless,
An excellent tutorial,but I can’t get the source code running;I am able to open the window “OpenGL 3 Project”,but I’m unable to visualize either the color or the square and the infinite loop just keeps running on..What is the error and how do I visualize the square and blue color on the OpenGL window?
i got 2 first chance exception when running the code, reading documentation they aren’t critical , but something isn’t going to be done properly.
Just wanted to signal this
to program opengl with windows api makes opengl suck
Hey Swiftless I have a suggestion and a question for you…
First the suggestion. You state that “CreateWindowEx method doesn’t support char arrays,” when in fact it does. Either unset MBCS and/or unicode in your project options or put #undef MBCS and/or #undef UNICODE in your files. If you’d like to know more on the subject, I suggest checking out Petzold’s Programming Windows API 5th Chapter 2.
Second, my question. I have successfully created both a Window, and an OpenGL context. I’m able to get the version info out of it, but nothing is drawing to the window.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glFinish();
if(!SwapBuffers(engineWindow->getDeviceContext())){
loggingManager->addError(__FILE__, “SwapBuffers()”, __LINE__, GetLastError());
}
Hey Frost,
I’m curious about how that works, I’m going based on the MSDN API reference, which takes an LPCTSTR:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
Have you since had any luck with this?
Thanks,
Swiftless
The sample code doesn’t include any “drawing” code, just all the stuff you need other than actually drawing anything (rendering) in OpenGL. You need to add code after the glClear call, and before the SwapBuffers call, that draws something.
That’s correct. This tutorial is simply on how to set up the window. Drawing of actual objects comes in later tutorials.
Cheers,
Swiftless
Can you give idea how to do this on linux with glx
“This means calls such as glRotate and glTranslate are not deprecated and not recommended.”
I’m thinking the first “not” should be a “now”, or just removed.
Thanks Ziusudra,
This has been updated!
Cheers,
Swiftless
not in the pdf though
So is this for OpenGL 4.0 or 3.0?
Hi OPENGL,
Both. They were originally written for 3.x, but with 4.x in mind. The setup for both 3.x and 4.x are identical, all you need to change is the version number. Keep in mind with 4.x that items deprecated in 3.x have since been removed totally. I have tried to avoid all deprecated methods so there should be no issue with OpenGL 4.x.
Thanks,
Swiftless
Why is wglChoosPixelFormatARB not used?
I was wondering why you arent using “wglChoosePixelFormatARB”?
Can we still use the full supported 3.x or higher rendering context without the use of “wglChoosePixelFormatARB”
Hey
i’m kinda confused right now… Is this the most up to date 1st tutorial or is this one http://www.swiftless.com/tutorials/opengl/window.html (opengl window version 2) more up to date/better? The other one certainly seems shorter and more to the point, without all the windows specific jibberjabber (reminds me of SDK…). Is it using deprecated features or will it work with opengl 3+ ?
I went through this entire tutorial only to be greeted with a linker error at the end. Turns out I had to switch from console to windows in linker settings to make it compile and run. But I thought this was a console app, not a windows app?
As i said, kinda confused right now :p
Hey Christer,
Sorry for the confusion. The OpenGL Window Version 2 is the most up to date tutorial for OpenGL 2.x and earlier. While the OpenGL 4 section of the site is solely for OpenGL 3.x and 4.x.
I’m not sure if FreeGLUT supports OpenGL 3.x and 4.x contexts, but if it does, you can definitely go ahead and use GLUT to get rid of all the windows specific jibberjabber. But the regular OpenGL section of the site is using functions deprecated and eventually removed from OpenGL 3.x and 4.x.
If you want to learn the older style of OpenGL, use the tutorial link you provided. If you want to learn the new style of OpenGL follow this section of the site.
I tried to point out that one of the main differences is that we are now using a Windows app and not a Console app like GLUT requires.
Cheers,
Swiftless
Thanks for the quick reply 🙂
You might want to change this sentence near the top, under coding, then:
This tutorial is going to be very similar in some ways to most Win32 OpenGL tutorials available, the only difference being that it has an OpenGL 3.2 context instead of a standard context. So open up Visual Studio and create a new Windows Console Application in C++.
😉
Judging from a couple other opengl3.3 tutorials i’ve found freeGLUT does indeed support opengl 3+ … but everywhere’s such a mess of 2.x and 3.x mixed up, not specified etc that it isn’t exactly easy to be sure of…
But let me see if i’m understanding stuff correctly… The big diff between 2.x and 3.x + is you need to program the pipeline yourself and it’s all shaderbased right? But for just showing a window you’re not really touching on that yet are you?
Or is setting up the contexts like you’re doing here also a required part of 3+ ?
Sorry for the noob questions, I’m having a hard time even getting started properly with OpenGL because of what seems like a lack of cold hard facts… :/
And as you can probably tell, i haven’t quite grasped what this context-stuff really is yet :p
Cheers for that! No one else has picked up on it (makes me wonder how many read it all ;).
Yes that’s the big difference, however pipeline might not be the best term. They have effective removed the immediate mode and gone for a GPU/Shader based approach very similar to Direct3D.
While creating a Win32 window isn’t anything to do with OpenGL, this tutorial is important because with OpenGL 3+ you need to specifically say what kind of context you want so that OpenGL can say whether it wants to follow the old pipeline or the new pipeline.
I hope that helps clear it up.
Cheers,
Swiftless
Hello,
I have tried to run your project, downloaded GLEW, followed installation instructions,
now the project finds the headers but, I am getting the following errors now :
Error 2 error LNK2001: unresolved external symbol __imp____wglewCreateContextAttribsARB
\opengl_3.obj
Error 3 error LNK2019: unresolved external symbol __imp__wglewIsSupported referenced in function
“public: bool __thiscall OpenGLContext::create30Context(struct HWND__ *)” (?create30Context@OpenGLContext@@QAE_NPAUHWND__@@@Z)
\opengl_3.obj
Error 4 error LNK2019: unresolved external symbol __imp__glewInit referenced in function
“public: bool __thiscall OpenGLContext::create30Context(struct HWND__ *)” (?create30Context@OpenGLContext@@QAE_NPAUHWND__@@@Z)
\opengl_3.obj
Is there something I am missing ?
Thank you 🙂
I just fixed it by getting 32-bit GLEW … Thank you !
I had identical problems, but in my case, my glew32.lib file was bad (I don’t know enough about MS tools to figure out why). Googling error LNK 2001 lead me to “Linker Tools Error LNK2001”, an MSDN page that mentions compiler versions as being sufficient to cause this error.
My solution was to build the library on my 64 bit Win 7 system. The converted projects (see below) built with errors associated with differences in the target name. The following steps include my fixes.
* downloaded the GLEW src (note: src zip file, not the binary versions)
* opened \build\vc6\glew.dsw in VS2010
* allowed VS to convert everything
* selected the glew_shared project, right clicked, and selected options
* pressed the Configuration Manager button in the upper right
* changed the Active solution configuration: from Debug to Release
* in the left hand panel, selected Configuration Properties|General
* edited Output Directory, was .\../../lib\ changed to .\../../bin\
* edited Target Name, was $(ProjectName) changed to glew32 (not glew32.lib)
* selected the glew_shared project and then the menu Build|Build glew_shared
***** \lib\glew32.lib is now ready for installation
* copied glew32.lib to,
\Microsoft Visual Studio 10.0\VC\lib\
The tutorial then built without error. Please forgive the explicit steps; I hope they help another newbee like me.
Thanks for the great tutorial Swiftless. M
Swiftless,
Thanks a lot for this enligthening tutorial. I have one question regarding the new 3.2 context:
Is it possible to continue to use older stuff (like glBegin() etc…) with the new 3.2 (or higher) context, or do you need to use an “old” context in order to access the old functions?
Background to my question: Within my project, I am using an application extension that comes as a precompiled library. On my side of the code, I can create and manipulate the context and call whatever function necessary. But I have no control over the code within the extension library, which is written to – i guess – 1.2 standard. (VC++ 6.0 Windows 2000/XP or Irix 6.4) I am actually quite keen to use all the new OpenGL features on my side of the code. But I have no clue whether that could work together with the “old” code in the extension library.
– do you think it might work out of the box?
– do you see a possiblity that works if I use the 3.2 context for my own rendering and to keep a, 2.1 context that I pass down to the library?
– Or, is your advice “to stick with 2.1 if you *have* to use 2.1 OpenGL code”.
Hi Willi,
That is a damn good comment!
I don’t have any experience in this, but here is how I would see it:
In short, you shouldn’t have any major issues (initially). OpenGL 3.x deprecated most of the immediate mode but it didn’t remove it (so technically they should still work, but aren’t guaranteed based on who implements the OpenGL support for your system). They weren’t removed from the specification until OpenGL 4.x and this is where things will get really picky.
I don’t see any reason why you can’t include a library that uses older OpenGL code in an OpenGL 3.x and earlier application. The reason we define an OpenGL 3.x and higher context specifically is because of the lack of backward compatibility with all the deprecated methods, we are simply telling OpenGL to follow this path of rendering instead of the older path.
This link might help in understanding the contexts:
http://www.opengl.org/registry/specs/ARB/wgl_create_context.txt
Personally I would recommend sticking with OpenGL 2.1 if you *have* to use OpenGL 2.1 code as it is implementor specific trying to mix in deprecated methods and there is always a chance that mixing the different functionality could break your application.
I’ve used OpenGL 2.1 code in OpenGL 3.x applications without any problems, but that was on Windows 7 with up to date Nvidia drivers. You may find that different drivers and different graphics card vendors, cause parts of OpenGL 2.1 and earlier to break when used in an OpenGL 3.x context.
Hope this helps,
Swiftless
I would like to bump
>createWindow(L”OpenGL 3 Project”, 500, 500);
and
>if (WGLEW_ARB_create_context)
could be used instead of
>if (wglewIsSupported(“WGL_ARB_create_context”) == 1)
Overall i like the tutorial ^^ and here’s something i changed.. might be interesting for others.
Below outputs “Attempting to use OpenGL 5.0
Falling back to OpenGL 4.1
Using OpenGL: 4.1”
>>>
if (WGLEW_ARB_create_context) { // If the OpenGL 3.x context creation extension is available
int attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 5, // Set the MAJOR version of OpenGL
WGL_CONTEXT_MINOR_VERSION_ARB, 0, // Set the MINOR version of OpenGL
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, // Set our OpenGL context to be forward compatible
0
};
printf(“Attempting to use OpenGL %d.%d\n”, attributes[1], attributes[3]);
hrc = wglCreateContextAttribsARB(hdc, NULL, attributes); // Create an OpenGL context based on the given attributes
// if failed, create using latest supported OpenGL version
if(!hrc)
{
/*
* Querying the GL_VERSION string with glGetString (or the
* GL_MAJOR_VERSION and GL_MINOR_VERSION values with glGetIntegerv, in
* a 3.0 or later context) will return the actual version supported by
* a context.
*/
glGetIntegerv(GL_MAJOR_VERSION, &attributes[1]);
glGetIntegerv(GL_MINOR_VERSION, &attributes[3]);
hrc = wglCreateContextAttribsARB(hdc, NULL, attributes); // Create an OpenGL context based on the given attributes
printf(“Falling back to OpenGL %d.%d\n”, attributes[1], attributes[3]);
if(!hrc)
hrc = tempOpenGLContext;
}
<<<
Hey Swiftless, I noticed that you are using the CreateWindowEx function with a wide character type. In my knowledge, the default is that Windows defaults it to CreateWindowExA which is the ascii version and does not support the wide character type. Defining the constant “UNICODE” before including window.h should fix this. Also instead of converting the character array to a wide character array, you can use the macro TEXT(qoute) which automatically switches between wide character and ascii characters depending on if UNICODE is defined. I had problems before I Googled this so I hope this also helps other people if you revise the project files and tutorials like this. (The TEXT macro makes things easier to switch back and forth in between ascii and unicode too!) Thanks.
hello swiftless ., i had execute your code and get the output in the temp.txt file and the amazingly the output is “Using OpenGL: -1.-1” but as per the code says the extension should me changed and the current version of opengl should be displayed.,
please tell me what to do i am using HP laptop DV2701tu model.,
please tell me ., i am a newbie to all this., please help me..
why me laptop not able to support 3.x version of OPENGL……..
Hi, I’ve been having problems getting this program to work. The program will compile and run but then exit immediately. As far as I can tell it’s posting WM_QUIT on the third iteration through the main loop without ever making a call to openglContext.renderScene().
The only changes I made to my code from the way it is in the tutorial is to put all the Windows specific calls in a class by itself and compile it on Codeblocks instead of Visual Studio (having to manually link libraries instead of using #pragma comment).
I’m really new to Windows programming so I don’t know why WM_QUIT is being posted when nothing seems to be doing anything that would generate it.
hello all, i have read many of OPENGL tutorials but still m not able to build even a “Hello World” program in my Visual studio 2010., please tell me wheather this tutorial orks on viual studio 2010 (W32 console application) ?
i am a newbie to OpenGL
please suggest me the ebook as well.
thankx in advance.,
Hi Karan,
Its will be more easy to help you, if you can tell us why you are not able to build your programs, like, you can paste your compile errors etc…
OpenGL programming guide by Dave shreiner oth…is a good book to start with….
And yes, these tutorials work with VS2010.
Happy GL coding,
Cheers.
sorry for the inconvenience n miss-understanding, i have run the other code of opengl ., and due to some lake of property adjustments and libraries files i was not able to execute my code., a very very thank to you i really need what i want from a good tutorial. i want a full pdf file of this tutoriald except one by one lessions tutorials., will you please send me the tutorials at karankumar1609@gmail.com ., because i am not able to get online tomy pc., thnx for reply.,
**********HAPPY CODING**********
I’d just like to state for the record that there is a huge difference between a Win32 Console Application, and a Win32 Project in VC++ 2010 Express.
Following this tutorial will result in much frustration unless you make it from a Win32 Project.
Hi Ben,
I have been using Visual Studio 2010 Professional and can confirm that everything must be done as a standard Win32 Application for my OpenGL 3/4 tutorials. All previous tutorials done in OpenGL 2 require a Win32 Console Application for GLUT to work.
Cheers,
Swiftless
Hi,
I started with the openGL tutorials which use GLUT and in this tutorial you have used winAPI (I am not much familiar with it).
What should I prefer if I have to enter the professional openGL zone?
Hi Paras,
I would recommend switching from GLUT if you want to have full control over your application. Theoretically if you want the portability of GLUT, you could get the GLUT sourcecode and make the changes you require. But even though you will be hard pressed getting threading integrated in a cross-platform solution, let alone different methods of input.
Cheers,
Swiftless
You can also use SDL, is better than GLUT, you have more control over your window and is multy-platform and free!! The problem is the current stable version 1.2 doesn’t support OpenGL 3/4 context, only the last (and unstable) version support OpenGL 3/4 but it isn’t officially released as a external library, you must download the source code and compile it or download a compiled version of another programmer. The 1.2 can be downloaded as external library from SDL web page: http://www.libsdl.org/
Hey,
Just finished the tutorial,
Im not sure what to put for the first part of code, the includes and pragma once some don’t have the files to include also i thought there would be some linking necessary not sure though,
if you could put this in the tutorial or e_mail me that would be great
Cheers
Hi Erian,
All linking is done via the “#pragma comment()” lines so you don’t have to link in the project settings.
However I see what you mean, that must have been a copy and paste issue when creating the tutorial. I’ll fix it up. In the meantime, there should be code in the VS2010 project I supply for that.
Cheers,
Swiftless
Hello,
I just finished this tutorial but I’m getting some problems compiling it.
If it matters, I’m using CodeBlocks since I like it better than VS. The problem I’m getting is a bunch of undefined references to some functions. It says all of these are undefined:
ChoosePixelFormat
SetPixelFormat
_imp__glewInit
_imp_wglewIsSupported
_imp___wglewCreateContextAttribsARB
SwapBuffers
Do you have any idea what could be wrong? I thought it might be because I’m using CodeBlocks, but I just tried with Visual Studio 2010 and it says these external symbols are unresolved:
__imp____wglewCreateContextAttribsARB
__imp__wglewIsSupported
__imp__glewInit
Nevermind, I guess I can’t use the glew 64bit files even when using 64bit Windows 7. I downloaded the 32bit version of glew and everything seems like it’s working fine.
Hey
I’ve searched everywhere for the opengl 3.0 and 4.0 librarys and i cant find them. Any idea on when they can be found?
Hi Andy A,
The libraries themselves (dll’s) should come with your graphics card. As for the .h and .lib files for your compiler, they come with GLUT and GLEW.
Cheers,
Swiftless
Hi Andy A.
The window’s dll opengl32 is no longer updated sins OpenGL 1.2 and actually krhonos publish a specification that is implemented by grafic cards vendor. I recomend you to use GLEW, this lib checks if every function of the API specification is implemented in your graphic card and create a pointer to it.
Just wanted to say thanks, awesome starting point for openGL newcomers!
Hi Swiftless, your tutorials are really good to learn modern opengl programming. I have a question about buying a book about this topic, i found that OpenGL SuperBible 5th edition is very recommended to learn new opengl stuff, what’s your opinion? do you know about other good books to learn opengl 3/4 programming (a part for your toturials that are one of the best sources i found).
Thanks!
Oh, a little improvement, you don’t need to write all the conversion code for the window title string, you can use a built-in conversor with much less code, the L”a tring” conversor:
createWindow(L”OpenGL 3 Project”, 800, 600);
Hey David,
I’ll check that out, thanks.
Cheers,
Swiftless
Simple but nice tutorial. One suggestion is that you should put all Windows related stuff inside another class, this will open opportunities and simplify the code and other tutorials by abstracting this layer.
Hi Danny,
I agree it is a lot nicer to put all the Windows related stuff into a separate class (by Windows, I’m assuming you mean the Windows specific calls such as window creation?). I even thought about this, as you can see I have put all the OpenGL related calls into their own class, and everything else I add in the future such as texturing, will be in it’s own class and then used by the OpenGL class, apart from platform specific functions such as keyboard and mouse interaction, which I plan to keep in the main.cpp file for now.
I’ll keep it in mind however, but at this stage, main.cpp is my link between OpenGL and Windows, and I don’t see a real need to change this. Especially when it will take quite a bit of time to rewrite the current tutorial, when I would rather spend that time going further into OpenGL 4 for everyone.
Cheers,
Swiftless
Thanks, you are a big help in diffrentiating between the versions and it’s working. i will prefer to go through basic first. it will always be helpful in long terms 🙂
Hi,
Your work is excellent. Very detailed. I just completed the first lesson, glanced through the old opengl tutorials and have a question to ask.
In your old opengl tutorials, you opted to use freeglut to handle your windows but in your new tutorials, you chose to handle the windows yourself through the windows API, what caused you to make this change?
Are there any advantages for one method over the other?
Thank you for your great work in producing these tutorials and publishing them! I was having a hard time looking for a comprehensive up-to-date tutorial on opengl.
Hi HJ,
This is a difficult question to actually answer in regards to OpenGL 3.x and up. I haven’t been able to find any documentation saying that FreeGLUT even supports the new calls required to set up and OpenGL 3.x and 4.x context on Windows and other machines.
I will however say straight out that GLUT and FreeGLUT should only be used in quick prototyping applications. The reason is that you don’t get control over your application. Managing everything yourself is a much nicer way to work with OpenGL and while OpenGL 3.x and 4.x have been updated to place more work on the developer, it is for the better of the API and you should not limit yourself to libraries such as GLUT which are only there as basic niceties. Unfortunately this does mean that your application is not cross-platform compatible from a windowing standpoint. In the computer graphics world, it is also often seen that use of GLUT will make you out to be unprofessional.
Cheers,
Swiftless
Hey,
Just finished the tutorial. It was very well written, and extremely understandable. I had a few issues setting up OpenGL, but that’s a problem on my computer’s end. I did have a question, though. On the older OpenGL’s tutorial’s page, you said you weren’t going to waste everyone’s time by rewriting those ones, since OpenGL 4 came out. How much changed between 2 and 4? I read your section on this tutorial, saying that 3 and 4 are more shader-based, and that there were significant changes, but is it still worthwhile to learn the older versions of OpenGL? Do many of the same concepts carry over, or has it been completely revamped?
In short, in your opinion, should I go through the older tutorials, or not?
Once again, this was very well written, very comprehensive, and very high quality. Truly, it is the best tutorial I have found so far, and I look forward to the others!
Hey Robert,
That is a really good question. OpenGL 2.1 and lower is supported on virtually all graphics cards on the market today, including integrated chips in laptops, so it can be considered a good idea to learn it if you want the backwards compatibility. However, a lot of what I will be doing in the OpenGL 3 and 4 tutorials can be done in lower versions of OpenGL through extensions. Some things however, such as Geometry shaders and tessellation, and the more advanced features are specific to OpenGL 3 and 4. Personally I would say it is easier to learn the new versions of OpenGL and then apply that to earlier versions, instead of the other way around.
I’ll give a quick idea of how it can be similar and different:
1. Matrices and transformations (translate, scale, rotate) – OpenGL 2.1 and lower has built in matrix models, however you can still create your own matrices and pass them to GLSL shaders. OpenGL 2.x introduced GLSL as part of the core, and prior versions such as OpenGL 1.5 allow GLSL through extensions. So this is no problem, you can work with matrices the same in both new and old versions of OpenGL by managing them yourself.
2. Geometry – OpenGL 2.1 and lower have the immediate mode available for rendering shapes, while in OpenGL 3 and up you need to use Vertex Buffer Objects and Vertex Buffer Arrays, etc. However Vertex Buffer Objects are available in earlier versions of OpenGL through extensions, and I have a tutorial on them in both the OpenGL and terrain section of the site. I believe Vertex Buffer Arrays are new though, and allow some new capabilities and I will go over them in one of the upcoming tutorials.
3. In-built Lighting Models – Earlier versions of OpenGL had lighting models, you are now required to handle all of this manually, and just like with matrices, it is no problem if you create the lights and their details themselves, and pass them through to your shaders.
4. etc, etc.
A lot of what is in the new OpenGL is available in the old OpenGL versions, but a lot of what is in the old OpenGL versions is not in the new OpenGL versions if that makes any sense. Doing everything the new way makes sure everything is efficient and how you want. But if you go over the older tutorials, it gives you a more basic idea into computer graphics and what can be done.
Cheers,
Swiftless
i think GLUT is perfect for starters/tutorials, demos and proofs of concepts. But in a “real World” app you must use OS-Specific API to create and manage your window/buffers.