Hello openGL users!
I have been trying for a week now to create a good working Win32 OpenGL 3.3 context.
I have tried to it the same way as in the following tutorial
http://www.swiftless.com/tutorials/opengl4/1-opengl-window.html
it works but it does not use the wglChoosePixelFormatArb(); so you cant use MSAA and newer stuff.
I have the newest OpenGL superbible 5 book and Beginning OpenGL Game Programming, Second Edition.
System:
I5 2500k CPU
2x 560 GTX TI SC
OpenGL 4.1 compatible
newest drivers
The problems I am having are:
- when sizing the window it show the windows DC background color around the openGL viewport.
- the window does not resize the way I want the mouse keeps sticking to the border.
http://imageshack.us/photo/my-images/695/renderingerror00.jpg/
http://imageshack.us/photo/my-images/90/renderingerror01.jpg/
Libraries used:
GLEW 1.7.0
Win32
Source:
program.cpp
/*
* Author: Mark van der Wal
* Date: 28-08-2011
* Descr: starting point of the application
*/
// libraries
#include "CGameForm.h"
#include <string>
// global definitions
const std::string gAppName = "OpenGLWin32Framework v0.1";
const unsigned int gWindowWidth = 1024;
const unsigned int gWindowHeight = 768;
// @STARTING_POINT
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
// create instance of a window
CGameForm game(hInstance, gWindowWidth, gWindowHeight, gAppName.c_str());
// try to create the main window
if( !game.CreateForm())
{
MessageBox(0, "Could not create Window!", "Error", MB_OK);
return 0;
}
// run the application
return game.RunApplication();
}
CGameForm.h
/*
* Author: Mark van der Wal
* Date: 28-08-2011
* Descr: Class for handling win 32 system operations and initializing OpenGL rendering context
*/
#ifndef _CGAMEFORM_H_
#define _CGAMEFORM_H_
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#include <GL/glew.h>
#include <GL/wglew.h>
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "opengl32.lib")
// Abstract base Window class
class CGameForm
{
public: // methods
// default constructor
inline CGameForm(const HINSTANCE& instance, USHORT width, USHORT height, LPCSTR caption)
: mHInstance(instance), mWindowName(caption)
{
memset(&mWindowDim, 0, sizeof(RECT));
mWindowDim.bottom = height;
mWindowDim.left = width;
mWindowDim.right = 0;
mWindowDim.top = 0;
}
// create the main app window
bool CreateForm();
// handle the events
int RunApplication();
private: // methods
// Message handlers
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT ProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
// tries to create the OpenGL rendering context
bool CreateRenderingContext(HWND hwnd);
private: // data members
HINSTANCE mHInstance; // handle to the instance the window belongs to
HWND mForm; // handle to the created window
HDC mFormDC; // device context
HGLRC mGLRC; // rendering context
// window data
LPCSTR mWindowName; // name of the window
RECT mWindowDim;
};
#endif // _CGameForm_H_
CGameForm.cpp
/*
* Author: Mark van der Wal
* Date: 28-08-2011
* Descr: Win32 abstract class, handles initializing a window on windows
*/
#include "CGameForm.h"
#include <string>
bool CGameForm::CreateForm()
{
// create the win32 class
// if we fail to create the Win32 class we return false
WNDCLASS pClass;
memset(&pClass, 0, sizeof(WNDCLASS));
// fill in the Win32 class structure
pClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
pClass.lpfnWndProc = CGameForm::WndProc;
pClass.cbClsExtra = NULL;
pClass.cbWndExtra = NULL;
pClass.hInstance = mHInstance;
pClass.hIcon = ::LoadIcon(mHInstance, IDI_APPLICATION);
pClass.hCursor = ::LoadCursor(0, IDC_ARROW);
pClass.hbrBackground = NULL;
pClass.lpszMenuName = NULL;
pClass.lpszClassName = mWindowName;
// try to register
if( ::RegisterClass( &pClass ) == 0 )
return false;
// create DUMMY window
HWND mFormTemp = ::CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
mWindowName, // class name
mWindowName, // window name
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
mWindowDim.right, mWindowDim.top,
mWindowDim.left, mWindowDim.bottom,
NULL,
NULL,
mHInstance,
NULL);
// create the rendering context
if( !CreateRenderingContext(mFormTemp) )
return false;
// set OpenGL state
glClearColor(0.2f, 0.7f, 1.0f, 1.0f);
// show & update the window
ShowWindow(mForm, SW_SHOW);
UpdateWindow(mForm);
return true;
}
// tries to create the OpenGL rendering context
bool CGameForm::CreateRenderingContext(HWND hwnd)
{
// for the 2.1 rendering context
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.iLayerType = PFD_MAIN_PLANE;
// get the device context for the 2.1 rendering context
HDC mFormDCTemp = GetDC(hwnd);
// choose most appropiate pixelformat for 2.1 rendering context
int pxFormat = ChoosePixelFormat(mFormDCTemp, &pfd);
if(pxFormat == 0)
return false;
// set the pixelformat to our window for 2.1 rendering context
bool result = SetPixelFormat(mFormDCTemp, pxFormat, &pfd);
if(!result)
return false;
// Create 2.1 rendering context and make it current
HGLRC tempGLRC = wglCreateContext(mFormDCTemp);
// error check
if( tempGLRC == 0)
return false;
// make the 2.1 Rendering context current
wglMakeCurrent(mFormDCTemp, tempGLRC);
// init GLEW
GLenum err = glewInit();
if(err != GLEW_OK)
return false;
// If the OpenGL 3.x context creation extension is available
if (wglewIsSupported("WGL_ARB_pixel_format") == 1)
{
// specify the attributes for a 3.x+ rendering context
unsigned int nPixCount = 0;
int pixelFormats = 0; // nr of pixel formats
const int pixAttribs[] = {
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
0};
mForm = ::CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
mWindowName, // class name
mWindowName, // window name
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
mWindowDim.right, mWindowDim.top,
mWindowDim.left, mWindowDim.bottom,
NULL,
NULL,
mHInstance,
this);
// get the new 3.X window DC
mFormDC = GetDC(mForm);
// get a pixelformat for our 3.X or higher rendering context
wglChoosePixelFormatARB(mFormDC, &pixAttribs[0], NULL, 1, &pixelFormats, &nPixCount);
// check if we could load a valid pixelformat
if(pixelFormats != -1)
{
// set the pixel format for our 3.X or higher context
SetPixelFormat(mFormDC, pixelFormats, &pfd);
// attribute list for the renderin context
int attribs33[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
// create the openGL rendering context
// check if it succeeded
if (wglewIsSupported("WGL_ARB_create_context") == 1) // If the OpenGL 3.x context creation extension is available
{
mGLRC = wglCreateContextAttribsARB(mFormDC, NULL, attribs33); // Create and OpenGL 3.x context based on the given attributes
// release all and start over for real context
wglMakeCurrent(NULL, NULL); //remove the 2.1 rendering context from being active
wglDeleteContext(tempGLRC); // Delete the temporary OpenGL 2.1 context
ReleaseDC(hwnd, mFormDCTemp);
DestroyWindow(hwnd);
// Make our OpenGL 3.x context current
wglMakeCurrent(mFormDC, mGLRC);
}
}
else
return false;
}
else
return false;
return true;
}
// the finite loop for everything handled in real time
int CGameForm::RunApplication()
{
// we only use this structure in here
MSG mMsg;
// zero out the message structure
ZeroMemory(&mMsg, sizeof(MSG));
// if the message recieved is not WM_QUIT we do stuff
while(mMsg.message != WM_QUIT)
{
// if there is a message in the queue handle it and remove it from the queue
if(PeekMessage(&mMsg, 0, 0, 0, PM_REMOVE))
{
// get it over to the message handler of this window
TranslateMessage(&mMsg);
DispatchMessage(&mMsg);
}
// clear the window with the current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
SwapBuffers(mFormDC);
}
// return the return code if the message handler terminates
return (int)mMsg.wParam;
}
// the static windproc callback function
LRESULT CALLBACK CGameForm::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// set the this pointer of the calling class in the user defined space
if( msg == WM_CREATE)
SetWindowLong(hwnd, GWL_USERDATA, (LONG)((CREATESTRUCT FAR*)lParam)->lpCreateParams);
// get the instance of this class
CGameForm* destination = (CGameForm*)GetWindowLong(hwnd, GWL_USERDATA);
// if it is not null we pass in the message to the local message handler
if(destination)
destination->ProcHandler(hwnd, msg, wParam, lParam);
// if non of the above is handled we let windows handle the message
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// the message handler
LRESULT CGameForm::ProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_SIZE:
mWindowDim.right = LOWORD(lParam);
mWindowDim.bottom = HIWORD(lParam);
// change the openGL viewport dimensions
glViewport(0, 0, mWindowDim.right, mWindowDim.bottom);
break;
case WM_DESTROY:
// check if we can delete the RC
if(mGLRC)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(mGLRC);
mGLRC = NULL;
}
if(mForm != NULL)
{
// check if we can delete the DC
if(mFormDC)
{
// release the DC
ReleaseDC(mForm, mFormDC);
}
// destroy the window
DestroyWindow(mForm);
}
// terminate the application
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}