不理解为什么上下文创建失败了win32 api和OpenGL和wgl

时间:2016-12-30 15:24:56

标签: c opengl wgl

所以我已经遵循了Windows创建中用于OpenGL渲染上下文的所有基本指令

问题是当我尝试使用opengl创建核心配置文件上下文时,它会失败并且我得到"程序停止工作"来自Windows的消息当我运行a.exe文件时,没有迹象表明存在问题以及导致问题的原因,我甚至尝试运行gdb但它只引用了函数

wglCreateContextAttribsARB,没有提供其他信息

这是我目前包含在程序中的文件

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;
}

最后是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);

}

现在,如果我这样做没有wglCreateContextAttribsARB的旧方法它工作正常并且即使没有着色器它也应该做什么,但是当我尝试通过使用wgl创建核心配置文件上下文时,程序失败< / p>

我用

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

并且没有给出错误

2 个答案:

答案 0 :(得分:2)

我们来看看你的代码:

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

您的评论

  

为了使用ARB上下文创建,必须创建一个渲染上下文必须被激活并销毁

尤其具有误导性。它不是为了创建和破坏一些遗留的上下文。它是关于创建一个上下文来获取WGL扩展函数指针,这是你根本不做的。

由于您正在使用GLEW的wglew功能,它将在wglew.h中声明所有必需的函数指针,但这些函数指针都已初始化为NULL,因此您对wglCreateContextAttribsARB的调用将只需取消引用NULL指针并崩溃。

创建并使当前的传统OpewGL上下文不会神奇地初始化这些指针。您必须明确地调用wglewInit()来查询这些函数指针 - 这是您需要tempContext处于活动状态的唯一时间。

答案 1 :(得分:2)

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

这不是你create a temporary rendering context的原因。

在Win32中,您可以直接访问基本的WGL功能。但是WGL扩展函数要求您已经具有渲染上下文,因为该实现实际上是提供这些扩展的。

因此,您创建一个临时上下文,然后加载WGL扩展,然后销毁临时上下文。

你跳过了中间部分。

此外,您不能将Win32 HWND的像素格式设置为一次。由于您可能希望使用WGL扩展来选择像素格式,因此这是一个问题。因此,应为临时窗口创建临时渲染上下文,您可以在其中设置临时像素格式。