Несмотря на чтение большого количества информации в Интернете, наряду с книгой Петцольда, Программирование Windows API , и, черт возьми, почти копирование точно такой же методологии из книги, наряду с это документация о том, как инициализировать контекст OpenGL, я не смог запустить и запустить Window Class.
Я попытался скомпилировать как VC ++, так и MinGW (я использую Qt Creator), чтобы посмотреть, сработает ли это. Я попытался сделать мой WNDCLASSEXA
указатель, а также разместить его в стеке. Никаких кубиков для обоих.
Таким образом, я совершенно не уверен, что с этим делать. Иногда класс просто не регистрируется, тогда как в другое время HWND
, который возвращается из CreateWindowExA
, просто не работает и возвращает NULL. После попытки просто продолжить программу, несмотря на происходящие инциденты, я получаю приложение, которое не может нарисовать окно.
Идея проста: у меня есть структура, которую я использую для простого хранения всех используемых данных (DEVMODEA
, WNDCLASSEXA
, HGLRC
и т. Д.).
Оттуда я использую эту структуру для создания окна, а затем передаю его вызывающей функции.
Все, что я действительно хочу сделать, это написать простую игру, похожую на понг, в OpenGL, используя GLSL / OpenGL 3.3. Для этого мне, очевидно, сначала нужен контекст, но я не могу понять, является ли проблема Qt Creator, Windows или чем-то еще.
Итак, что я могу делать не так?
GameData
Структура
typedef struct
{
HGLRC hrc;
HDC hdc;
HWND hwnd;
HINSTANCE hInstance;
UINT numFormats;
WNDCLASSEXA* winClass;
DWORD dwExStyle;
DWORD dwStyle;
RECT winRect;
DEVMODEA screenSettings;
bool fullscreen;
const char* winClassName;
int pixelFormat;
bool keys[ 256 ];
bool active;
}
GameData;
initPong()
функция
static GameData* initContextAndWindow( void )
{
GameData* dat = new GameData;
const int width = 640;
const int height = 480;
const int bitsPerPixel = 32;
dat->winRect.left = ( long )0;
dat->winRect.right = ( long )width;
dat->winRect.top = ( long )0;
dat->winRect.bottom = ( long )height;
dat->fullscreen = false;
dat->hInstance = GetModuleHandleA( NULL );
dat->winClass = ( WNDCLASSEXA* )calloc( sizeof( WNDCLASSEXA ), 1 );
if( !dat->winClass )
MessageBoxA( NULL, "Something wrong!", "ERROR", MB_OK | MB_ICONINFORMATION );
dat->winClass->style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
dat->winClass->lpfnWndProc = ( WNDPROC ) eventHandler;
dat->winClass->cbClsExtra = 1;
dat->winClass->cbWndExtra = 1;
dat->winClass->cbSize = sizeof( WNDCLASSEXA );
dat->winClass->hInstance = dat->hInstance;
dat->winClass->hIcon = LoadIcon( NULL, IDI_WINLOGO );
dat->winClass->hCursor = LoadCursor( NULL, IDC_ARROW );
dat->winClass->hbrBackground = ( HBRUSH ) GetStockObject( WHITE_BRUSH );
dat->winClass->lpszMenuName = NULL;
dat->winClass->lpszClassName = "PongDH";
if ( !RegisterClassExA( dat->winClass ) )
{
MessageBoxA( NULL, "Failed to register class.", "ERROR", MB_OK | MB_ICONINFORMATION );
exit( 1 );
}
if ( dat->fullscreen )
{
memset( &dat->screenSettings, 0, sizeof( dat->screenSettings ) );
dat->screenSettings.dmSize = sizeof( dat->screenSettings );
dat->screenSettings.dmPelsWidth = width;
dat->screenSettings.dmPelsHeight = height;
dat->screenSettings.dmBitsPerPel = bitsPerPixel;
dat->screenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if ( ChangeDisplaySettingsA( &dat->screenSettings, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
{
dat->fullscreen = false;
const int continuePlaying = MessageBoxA(
NULL,
"Could not implement fullscreen. Please check your drivers. Do you plan to continue?",
"ERROR",
MB_YESNO | MB_ICONEXCLAMATION
);
if ( continuePlaying == IDYES )
{
MessageBoxA( NULL, "Will revert back to fullscreen.", "Notifcation", MB_OK );
dat->fullscreen = false;
}
else
{
MessageBoxA( NULL, "The program will now close", "Notification", MB_OK );
exit( 1 );
}
}
}
if ( dat->fullscreen )
{
dat->dwExStyle = WS_EX_APPWINDOW;
dat->dwStyle = WS_POPUP;
ShowCursor( FALSE );
}
else
{
dat->dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dat->dwStyle = WS_OVERLAPPEDWINDOW;
}
AdjustWindowRectEx( &dat->winRect, dat->dwStyle, FALSE, dat->dwExStyle );
dat->hwnd = CreateWindowExA(
dat->dwStyle,
dat->winClass->lpszClassName,
"PongDH",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
dat->winRect.right,
dat->winRect.bottom,
NULL,
NULL,
dat->hInstance,
NULL
);
if ( dat->hwnd == NULL )
{
MessageBoxA( NULL, "Failed to create window; exiting program.", "ERROR", MB_OK | MB_ICONEXCLAMATION );
exit( 1 );
}
const int attrList[] =
{
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,
};
wglChoosePixelFormatARB( dat->hdc, attrList, NULL, 1, &dat->pixelFormat, &dat->numFormats );
const int contextList[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
0,
};
dat->hrc = wglCreateContextAttribsARB( dat->hdc, NULL, contextList );
if( !wglMakeCurrent( dat->hdc, dat->hrc ) )
{
MessageBoxA( NULL, "Error making OpenGL Rendering Context current.", "ERROR", MB_OK | MB_ICONEXCLAMATION );
exit( 1 );
}
ShowWindow( dat->hwnd, SW_SHOW );
SetForegroundWindow( dat->hwnd );
SetFocus( dat->hwnd );
resizeScene( width, height );
UpdateWindow( dat->hwnd );
glEnable( GL_DEPTH_TEST );
return dat;
}
Обновление
Здесь я опубликую процедуру того, что я сделал:
Сначала я попытался установить cbClsExtra
на 1, тогда как раньше было 0. Затем я установил cbWndExtra
на 1. После этого я попытался установить cbSize
на sizeof( WNDCLASSEXA )
.
Я также пытался компилировать под VC ++ и MinGW; в VC ++ класс просто не регистрируется, где, как и в MinGW, класс будет регистрироваться, но на самом деле он не создаст требуемый hwnd
.
Я также попытался отредактировать мой код, сделав WNDCLASSEXA
(что является dat->winClass
) указателем, в отличие от переменной, выделенной в стеке.
Я также закомментировал свои exit
функции в моих if
проверках, чтобы увидеть, регистрируется ли класс * , или hwnd
не создано. Это приводит к ошибке сегментации при попытке визуализации контекста OpenGL с wglChoosePixelFormatARB
.
Обновление 2
Вот мой WndProc:
LRESULT CALLBACK eventHandler( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
return DefWindowProcA( hwnd, uMsg, wParam, lParam );
}