Не понимаю, почему создание контекста не удается с Win32 API и OpenGL и WGL
Итак, я следовал всем основным инструкциям в создании окон для контекста рендеринга OpenGL
проблема заключается в том, чтобы сделать, когда я пытаюсь создать основной профиль профиля с помощью opengl, он не работает, и я получаю сообщение "программа перестала работать" из окон, когда я запускаю файл 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, происходит сбой программы
я собираю с
gcc -Wall -Werror mainWin.c -lopengl32 -lglew32 -lgdi32
и никаких ошибок не дано
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, чего вы просто не делаете.
Так как вы используете функциональность wglew GLEW, он объявит все необходимые указатели функций в wglew.h
, но все эти указатели на функции инициализируются NULL
Итак, ваш зов wglCreateContextAttribsARB
будет просто разыменовывать NULL
указатель и сбой.
Создание и создание текущего унаследованного контекста OpewGL не будет магически инициализировать эти указатели. Вы должны явно позвонить wglewInit()
запросить эти указатели функций - и это единственный раз, когда вам нужно tempContext
будучи активным.
//in order to use ARB context creation you must create a render context //must be made active and destroyed
Это не то, почему вы создаете временный контекст рендеринга.
В Win32 вы можете получить доступ к основным функциям WGL напрямую. Но функции расширения WGL требуют, чтобы у вас уже был контекст рендеринга, поскольку именно эта реализация и обеспечивает эти расширения.
Таким образом, вы создаете временный контекст, затем загружаете расширения WGL, затем уничтожаете временный контекст.
Вы пропустили среднюю часть.
Кроме того, вы не можете установить формат пикселей Win32 HWND более одного раза. Поскольку вы, вероятно, хотите использовать расширения WGL для выбора формата пикселей, это проблема. Таким образом, ваш временный контекст рендеринга должен быть создан для временного окна, где вы устанавливаете временный формат пикселей.