I'm trying to create an OpenGL context (Modern Version) using Windows functions.
Basically the code is just:
- Create window class
- Register the class
- create a Window
- choose
PIXELFORMATDESCRIPTOR
& set it - Create a legacy OpenGL context
- Make context current
glewInit()
- Create new window
- Create a modern pixel format attrib array
- Set the format
- Create modern OpenGL context
- Make context current
After this I try to draw a square (using a VAO & VBO).
The result is: the Windows window works, the glClear(GL_COLOR_BUFFER_BIT)
works, but the square is not drawn (display()
function).
If I use an OpenGL 2.0 context, it draws the square (using a VAO & VBO as before), so the problem must be on the init of OpenGL 3.2.
Where am I going wrong?
Here is the code:
#include <iostream>
#include <GL/glew.h>
#include <GL/wglew.h>
#include <windows.h>
#include <string>
using namespace std;
bool progRun = false;
void display(){
glUseProgram(shaderProg);
glBindVertexArray(vao[0]);
glDrawArrays(GL_QUADS, 0,4);
}
string errorStr = "none";
PIXELFORMATDESCRIPTOR pfd;
HGLRC hrc; // vars to init glew
HDC hdc;
HWND hwnd;
HGLRC hrc1; //vars for the real window
HDC hdc1;
HWND hwnd1;
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); // window event hadler prototype
//-------------------- INIT OPENGL
int initOpengl(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
//---- fake Window
WNDCLASSEX wcex;
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "coco";
wcex.hIconSm = NULL;
if( !RegisterClassEx( &wcex ) )
{
errorStr = "RegisterClassEx";
return 0;
}
hwnd = CreateWindow(
"coco",
"dddd",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500,
NULL,
NULL,
hInstance,
NULL
);
hdc = GetDC( hwnd );
memset( &pfd, 0, sizeof( PIXELFORMATDESCRIPTOR ) );
pfd.nSize = sizeof( PIXELFORMATDESCRIPTOR );
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int nPixelFormat = ChoosePixelFormat( hdc, &pfd );
SetPixelFormat( hdc, nPixelFormat, &pfd );
hrc = wglCreateContext( hdc );
wglMakeCurrent( hdc, hrc );
glewExperimental = true;
glewInit();
//---------------For the real window
if( wglewIsSupported( "WGL_ARB_create_context" ) == 1 )
{
wglMakeCurrent( NULL, NULL );
wglDeleteContext( hrc );
ReleaseDC( hwnd, hdc );
DestroyWindow( hwnd );
hwnd1 = CreateWindow(
"coco",
"ddddd",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500,
NULL,
NULL,
hInstance,
NULL
);
hdc1 = GetDC( hwnd1 );
const int iPixelFormatAttribList[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0 // End of attributes list
};
int attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3
, WGL_CONTEXT_MINOR_VERSION_ARB, 2
, WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
, 0
};
int nPixelFormat = 0;
UINT iNumFormats = 0;
wglChoosePixelFormatARB( hdc1, iPixelFormatAttribList, NULL, 1, &nPixelFormat, (UINT*)&iNumFormats );
SetPixelFormat( hdc1, nPixelFormat, &pfd );
hrc1 = wglCreateContextAttribsARB( hdc1, 0, attributes );
wglMakeCurrent( NULL, NULL );
wglMakeCurrent( hdc1, hrc1 );
}
else
{
errorStr = "WGL_ARB_create_context";
return 0;
}
return true;
}
// MAIN -----
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
initOpengl( hInstance, hPrevInstance, lpCmdLine, nCmdShow );
ShowWindow( hwnd1, SW_SHOW );
glClearColor( 1, 0, 0, 1 );
MSG msg;
progRun = true;
while( progRun )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
glClear( GL_COLOR_BUFFER_BIT );
glViewport( 0, 0, 500, 500 );
display();
SwapBuffers( hdc1 );
}
return 0;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
return DefWindowProc( hWnd, message, wParam, lParam );
}
The problem is not in the context creation code alone, but in the combination of the used OpenGL version and the drawing code.
When requesting an OpenGL context as it is done in the question, there are several attributes that can be set. The relevant one here is the
WGL_CONTEXT_PROFILE_MASK_ARB
(which is not set). The extension description states:This means that the code in the question requests a OpenGL 3.2 Core Profile in the not working version a 3.1 (compatibility) profile in the other case.
In a core profile, the use of
GL_QUADS
as mode forglDrawArrays
is deprecated and cannot be used. Due to this, the quad isn't rendered. Note, that you would have found the problem ways faster if you would check for OpenGL errors (glGetError
) in your code since it would have reported aGL_INVALID_ENUM
for the draw command.There are two ways how the problem can be solved:
GL_TRIANGLES
). This is the recommended way.WGL_CONTEXT_PROFILE_MASK_ARB
with the valueWGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
. But note, that this might cause problems in the future because mixing old OpenGL code with modern OpenGL can lead to problems.