Search code examples
copenglwgl

Not understanding why context creation failing with win32 api and OpenGL and wgl


So i have followed all of the fundamental instructions in windows creation for OpenGL rendering context

the problem is to do when i try to create a core profile context with opengl , it fails and i get the "the program stopped working" message from windows when i run the a.exe file, there is no indication where the problem exists and what is causing the problem , i even tried to run gdb but it only refers to the function

wglCreateContextAttribsARB and no other information is given

here is my files which are currently included in the program

mainWin.c

#include "mainWin.h"
#include "glPart.c"



//main function, point of entry for windows application 
//must be present in a windows application

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
               LPSTR lpCmdLine, int nCmdShow)
{
   MSG        Msg;  //variable for storing messages retrieved from operating system by using GetMessage
   HWND       hWnd;
   WNDCLASS   WndCls;

   // Create the window object
   //sends a WM_CREATE message to windows which doesnt get processed until you retrieve messages and process them 

   //initialize window class must be initialized no default class 
   initWinClass(&WndCls, hInstance);
   //Register the application must register application to make it available to other controls 
   RegisterClass(&WndCls);

   hWnd = CreateWindow(ClsName,
                       WndName,
                       WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       640,
                       640,
                       NULL,
                       NULL,
                       hInstance,
                       NULL);

   //printf("at initialization %x\n",hWnd);

   // Find out if the window was created
   if( !hWnd ) // If the window was not created,
      return 0; // stop the application

   printf("Window was created....\n");   

   // Display the window to the user
   ShowWindow(hWnd, SW_SHOWNORMAL);
   UpdateWindow(hWnd);

   initGL(hDC);

   //GLint a, b;

   while (Msg.message != WM_QUIT)
   {
      while (PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
      {
          TranslateMessage (&Msg);
          DispatchMessage (&Msg);
      }
     //Here is were all the "animation that isn't used when the user does something" code will go.
      renderTri();
      SwapBuffers(hDC);
   }

   return Msg.wParam;
}

winMain.h

#define true 1
#define false 0

#include <windows.h>
#include <stdio.h>
#include <GL/glew.h>
#include <GL/wglew.h>
#include <GL/gl.h>

LPCTSTR ClsName = "OpenGL App";
LPCTSTR WndName = "My Game";
//global hdc
HDC hDC;

PIXELFORMATDESCRIPTOR pfd = {
      sizeof(PIXELFORMATDESCRIPTOR),          //size of structure
      1,                                      //default version
      PFD_DRAW_TO_WINDOW |                    //window drawing support
      PFD_SUPPORT_OPENGL |                    //opengl support
      PFD_DOUBLEBUFFER,                       //double buffering support
      PFD_TYPE_RGBA,                          //RGBA color mode
      32,                                     //32 bit color mode
      0, 0, 0, 0, 0, 0,                       //ignore color bits
      0,                                      //no alpha buffer
      0,                                      //ignore shift bit
      0,                                      //no accumulation buffer
      0, 0, 0, 0,                             //ignore accumulation bits
      24,                                     //16 bit z-buffer size
      8,                                      //stencil buffer
      0,                                      //no aux buffer
      PFD_MAIN_PLANE,                         //main drawing plane
      0,                                      //reserved
      0, 0, 0 };                              //layer masks ignored

//context attributes
int attribs[] =
{
   WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
   WGL_CONTEXT_MINOR_VERSION_ARB, 1,
   WGL_CONTEXT_FLAGS_ARB, 0,
   WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 
   0
};


LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

void initWinClass(PWNDCLASS WndCls, HINSTANCE hInstance){

   // Create the application window
   //WndCls.cbSize        = sizeof(WNDCLASSEX); wndclassex
   WndCls->style         = CS_HREDRAW | CS_VREDRAW |CS_OWNDC;  
   //the style member variable specifies the primary operations applied on the window class
   //if user moves or changes its size, you would need the window redrawn to get its characteristics 
   //CS_HREDRAW CS_VREDRAW draw the window vertically and horizontally  
   WndCls->lpfnWndProc   = WndProcedure;
   WndCls->cbClsExtra    = 0;
   WndCls->cbWndExtra    = 0;
   WndCls->hIcon         = LoadIcon(NULL, IDI_APPLICATION);
   WndCls->hCursor       = LoadCursor(NULL, IDC_ARROW);
   WndCls->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //cast to HBRUSH 
   WndCls->lpszMenuName  = NULL;
   WndCls->lpszClassName = ClsName;
   WndCls->hInstance     = hInstance;
   //WndCls.hIconSm       = LoadIcon(NULL, IDI_APPLICATION); wndclassex

}

void setupPixelFormat(HDC hDC){

   int nPixelFormat;

   /*      Choose best matching format*/
   nPixelFormat = ChoosePixelFormat(hDC, &pfd);

   if (nPixelFormat == 0) printf("Error in choose pixel format\n");

   /*      Set the pixel format to the device context*/
   BOOL bResult = SetPixelFormat(hDC, nPixelFormat, &pfd);

   if (!bResult) printf("Error in set pixel format\n");


}

void setupPixelFormatARB(HDC hDC){

   const int attribList[] =
   {
     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
   };

   int pixelFormat;
   UINT numFormats;

   wglChoosePixelFormatARB(hDC, attribList, NULL, 1, &pixelFormat, &numFormats);
   SetPixelFormat(hDC, pixelFormat, &pfd);


}

LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
   //printf("the message %d memory address is %x\n", Msg, hWnd);   

   static HGLRC hRC;

    switch(Msg)
    {
    //this is the favourite message you can use to perform any early processing that you want to make 
    //sure happens before most things show up you can use this message to initialize anything in your application
    //The window procedure of the new window receives this message after the window is created, 
    //but before the window becomes visible.
    //will only run once on creation
    case WM_CREATE:
       hDC = GetDC(hWnd);   //get the device context for window
       setupPixelFormat(hDC); //call our pixel format setup function

       //in order to use ARB context creation you must create a render context
       //must be made active and destroyed 
       HGLRC tempContext = wglCreateContext(hDC);
       wglMakeCurrent(hDC, tempContext);

       hRC = wglCreateContextAttribsARB(hDC,0, attribs);
       wglMakeCurrent(NULL, NULL);
       wglDeleteContext(tempContext);
       wglMakeCurrent(hDC, hRC);

      wglMakeCurrent(hDC,hRC);  //make rendering context current old style
    break;

    //minimum application needs to deal with: 
    //wm_destroy message to close window and default case for non registered default messaging processing
    //otherwise hanging or not reaching event queue  

    case WM_DESTROY: //Sent when a window is being destroyed. 
                     //It is sent to the window procedure of the window being destroyed after the window is removed from the screen.
    //you can use this message to deconstruct the window once the user requests to destroy the window
       wglMakeCurrent(hDC,NULL);    //deselect rendering context
       wglDeleteContext(hRC);       //delete rendering context
       PostQuitMessage(0);      //The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately
       //send wm_quit message 
       //Indicates a request to terminate an application, and is generated when the application calls the PostQuitMessage function. 
       //This message causes the GetMessage function to return zero.
       printf("Window destroyed goodbye...bye");
    break;

    //this must exist to process left over messages or the application will hang or will not go forward through the 
    //event queue and the while loop will 
    default:
        // Process the left-over messages and messages that are not dealt with
       return DefWindowProc(hWnd, Msg, wParam, lParam);
    break;
    }
    // If something was not done, let it go
    return 0;
}

and finally glPart.c

#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>

void initGL(HDC hDC){

   //set experimental value to true so that all functions can be used
       glewExperimental = GL_TRUE;

       //initialize glew and get result , check result is not a failure 
       GLenum err = glewInit();
       if(err!=GLEW_OK){
          printf("glew failed!!!....");     
       }

   //wglGetProcAddress("wglGetExtensionsStringARB")

   printf("OpenGL version string is %s\n", glGetString(GL_VERSION));

   GLint OpenGLVersion[3];

   glGetIntegerv(GL_MAJOR_VERSION, &OpenGLVersion[0]);
   glGetIntegerv(GL_MINOR_VERSION, &OpenGLVersion[1]);

   printf("Glew version is %s\n", glewGetString(GLEW_VERSION));
   printf("GL Major version %d\nGL Minor Version %d\n", OpenGLVersion[0], OpenGLVersion[1]);
   printf("GLSL version is %s \nVendor of OpenGL is %s \nRenderer version is %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION), 
                                                                                    glGetString(GL_VENDOR) ,glGetString(GL_RENDERER));
   // Enable settings 
   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

}
void renderTri(){

   //finally some drawing OpenGL

   GLuint vao;
   glGenVertexArrays(1, &vao);
   glBindVertexArray(vao);

   // An array of 3 vectors which represents 3 vertices
   static const GLfloat verticies[] = {
     -1.0f, -1.0f, 0.0f,
      1.0f, -1.0f, 0.0f,
      0.0f,  1.0f, 0.0f,
   };

   // This will identify our vertex buffer
   GLuint vbo;
   // Generate 1 buffer, put the resulting identifier in vertexbuffer
   glGenBuffers(1, &vbo);
   // The following commands will talk about our 'vertexbuffer' buffer
   glBindBuffer(GL_ARRAY_BUFFER, vbo);
   // Give our vertices to OpenGL.
   glBufferData(GL_ARRAY_BUFFER, sizeof(verticies), verticies, GL_STATIC_DRAW);

   // 1rst attribute buffer : vertices
   glEnableVertexAttribArray(0);
   glBindBuffer(GL_ARRAY_BUFFER, vbo);
   glVertexAttribPointer(
      0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
      3,                  // size
      GL_FLOAT,           // type
      GL_FALSE,           // normalized?
      0,                  // stride
      (void*)0            // array buffer offset
   );
   // Draw the triangle !
   glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
   glDisableVertexAttribArray(0);

}

now if i do this the old way without wglCreateContextAttribsARB it works fine and does what it is supposed to do even without the shaders , but when i try to do this by creating a core profile context with wgl is when the program fails

i compile with

gcc -Wall -Werror mainWin.c -lopengl32 -lglew32 -lgdi32

and no error are given


Solution

  • Let's have a look at your code here:

    case WM_CREATE:
       hDC = GetDC(hWnd);   //get the device context for window
       setupPixelFormat(hDC); //call our pixel format setup function
    
       //in order to use ARB context creation you must create a render context
       //must be made active and destroyed 
       HGLRC tempContext = wglCreateContext(hDC);
       wglMakeCurrent(hDC, tempContext);
    
       hRC = wglCreateContextAttribsARB(hDC,0, attribs);
       wglMakeCurrent(NULL, NULL);
       wglDeleteContext(tempContext);
       wglMakeCurrent(hDC, hRC);
    
       wglMakeCurrent(hDC,hRC);  //make rendering context current old style
    

    Your comment

    in order to use ARB context creation you must create a render context must be made active and destroyed

    is especially misleading. It is not about creating and destroing some legacy context for its own sake. It is about creating a context to get the WGL extension function pointers, which you simply do not do.

    Since you are using GLEW's wglew functionality, it will declare all the necessary function pointers in wglew.h, but these function pointers are all initialized to NULL, so your call of wglCreateContextAttribsARB will just dereference the NULL pointer and crash.

    Creating and making current a legacy OpewGL context will not magically initialize these pointers. You have to explicitely call wglewInit() to query these function pointers - and that is the only time you need tempContext being active.