I was following this tutorial for my first attempt at OpenGL. All I'm doing is initializing an empty window. His VS 2010 code is here. Using Dev-C++ as my IDE on Windows 7, and MS SDK 7.1, I get this error:
[Linker error] undefined reference to `_imp____wglewCreateContextAttribsARB'
ld returned 1 exit status
[Build Error] ["My] Error 1
I have -lopengl32 and -lglew32 as my linker parameters, and I've tried adding -lglu32 too.
Here's my code.
Opengl_3.h
#pragma once
#include <windows.h>
#include <iostream>
#include <GL/glew.h>
#include <GL/wglew.h>
//#pragma comment(lib, "glew32.lib")
//#pragma comment(lib, "opengl32.lib")
/*
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:
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)
private:
int windowWidth; // Store the width of our window
int windowHeight; // Store the height of our window
protected:
HGLRC hrc; // Rendering context
HDC hdc; // Device context
HWND hwnd; // Window identifier
};
Opengl_3.cpp
#include "Opengl_3.h"
/*
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
}
/*
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
}
/*
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
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
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;
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
//glewExperimental = GL_TRUE;
GLenum error = glewInit(); // Enable GLEW
if (error != GLEW_OK) // If GLEW fails
return false;
int attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, // Set the MAJOR version of OpenGL to 3
WGL_CONTEXT_MINOR_VERSION_ARB, 3, // 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
};
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
}
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 MINOR 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”
return true; // We have successfully created a context, return true
}
/*
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)
}
/*
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
}
/*
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
}
main.cpp
#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
/**
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;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
bool createWindow(char *title, int width, int height)
{
WNDCLASS wc;
HWND hWnd;
hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = title;
if (!RegisterClass(&wc))
return false;
DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
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;
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
char title[] = "OpenGL 3 Project";
createWindow(title, 500, 500); // Create our OpenGL window
openglContext.setupScene(); // Setup our OpenGL scene
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;
}