173 lines
6.1 KiB
C
173 lines
6.1 KiB
C
/**
|
|
* Thanks to Xeek for the code!
|
|
*
|
|
* Building and running under Linux:
|
|
* i686-w64-mingw32-gcc example/c/wgl.c build/src/wgl.c build/src/gl.c -Ibuild/include -lgdi32 -lopengl32
|
|
* wine a.exe
|
|
*/
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <glad/wgl.h>
|
|
#include <glad/gl.h>
|
|
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
|
|
static const TCHAR window_classname[] = _T("SampleWndClass");
|
|
static const TCHAR window_title[] = _T("[glad] WGL");
|
|
static const POINT window_location = { CW_USEDEFAULT, 0 };
|
|
static const SIZE window_size = { 1024, 768 };
|
|
static const GLfloat clear_color[] = { 0.0f, 0.0f, 1.0f, 1.0f };
|
|
|
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
|
UNREFERENCED_PARAMETER(hPrevInstance);
|
|
UNREFERENCED_PARAMETER(lpCmdLine);
|
|
|
|
WNDCLASSEX wcex = { };
|
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcex.lpfnWndProc = WndProc;
|
|
wcex.hInstance = hInstance;
|
|
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
|
wcex.lpszClassName = window_classname;
|
|
|
|
ATOM wndclass = RegisterClassEx(&wcex);
|
|
|
|
HWND hWnd = CreateWindow(MAKEINTATOM(wndclass), window_title,
|
|
WS_OVERLAPPEDWINDOW,
|
|
window_location.x, window_location.y,
|
|
window_size.cx, window_size.cy,
|
|
NULL, NULL, hInstance, NULL);
|
|
|
|
if (!hWnd) {
|
|
MessageBox(NULL, _T("Failed to create window!"), window_title, MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
// Configure & Initialize OpenGL:
|
|
|
|
// Get a device context so I can set the pixel format later:
|
|
HDC hdc = GetDC(hWnd);
|
|
if (hdc == NULL) {
|
|
DestroyWindow(hWnd);
|
|
MessageBox(NULL, _T("Failed to get Window's device context!"), window_title, MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
// Set the pixel format for the device context:
|
|
PIXELFORMATDESCRIPTOR pfd = { };
|
|
pfd.nSize = sizeof(pfd);
|
|
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); // Set the size of the PFD to the size of the class
|
|
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; // Enable double buffering, opengl support and drawing to a window
|
|
pfd.iPixelType = PFD_TYPE_RGBA; // Set our application to use RGBA pixels
|
|
pfd.cColorBits = 32; // Give us 32 bits of color information (the higher, the more colors)
|
|
pfd.cDepthBits = 32; // Give us 32 bits of depth information (the higher, the more depth levels)
|
|
pfd.iLayerType = PFD_MAIN_PLANE; // Set the layer of the PFD
|
|
int format = ChoosePixelFormat(hdc, &pfd);
|
|
if (format == 0 || SetPixelFormat(hdc, format, &pfd) == FALSE) {
|
|
ReleaseDC(hWnd, hdc);
|
|
DestroyWindow(hWnd);
|
|
MessageBox(NULL, _T("Failed to set a compatible pixel format!"), window_title, MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
// Create and enable a temporary (helper) opengl context:
|
|
HGLRC temp_context = NULL;
|
|
if (NULL == (temp_context = wglCreateContext(hdc))) {
|
|
ReleaseDC(hWnd, hdc);
|
|
DestroyWindow(hWnd);
|
|
MessageBox(NULL, _T("Failed to create the initial rendering context!"), window_title, MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
wglMakeCurrent(hdc, temp_context);
|
|
|
|
// Load WGL Extensions:
|
|
gladLoaderLoadWGL(hdc);
|
|
|
|
// Set the desired OpenGL version:
|
|
int attributes[] = {
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, // Set the MAJOR version of OpenGL to 3
|
|
WGL_CONTEXT_MINOR_VERSION_ARB, 2, // Set the MINOR version of OpenGL to 2
|
|
WGL_CONTEXT_FLAGS_ARB,
|
|
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, // Set our OpenGL context to be forward compatible
|
|
0
|
|
};
|
|
|
|
// Create the final opengl context and get rid of the temporary one:
|
|
HGLRC opengl_context = NULL;
|
|
if (NULL == (opengl_context = wglCreateContextAttribsARB(hdc, NULL, attributes))) {
|
|
wglDeleteContext(temp_context);
|
|
ReleaseDC(hWnd, hdc);
|
|
DestroyWindow(hWnd);
|
|
MessageBox(NULL, _T("Failed to create the final rendering context!"), window_title, MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
wglMakeCurrent(NULL, NULL); // Remove the temporary context from being active
|
|
wglDeleteContext(temp_context); // Delete the temporary OpenGL context
|
|
wglMakeCurrent(hdc, opengl_context); // Make our OpenGL 3.2 context current
|
|
|
|
// Glad Loader!
|
|
if (!gladLoaderLoadGL()) {
|
|
wglMakeCurrent(NULL, NULL);
|
|
wglDeleteContext(opengl_context);
|
|
ReleaseDC(hWnd, hdc);
|
|
DestroyWindow(hWnd);
|
|
MessageBox(NULL, _T("Glad Loader failed!"), window_title, MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
// Show & Update the main window:
|
|
ShowWindow(hWnd, nCmdShow);
|
|
UpdateWindow(hWnd);
|
|
|
|
// A typical native Windows game loop:
|
|
bool should_quit = false;
|
|
MSG msg = { };
|
|
while (!should_quit) {
|
|
// Generally you'll want to empty out the message queue before each rendering
|
|
// frame or messages will build up in the queue possibly causing input
|
|
// delay. Multiple messages and input events occur before each frame.
|
|
while (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
|
|
if (msg.message == WM_QUIT || (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE))
|
|
should_quit = true;
|
|
}
|
|
|
|
glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
SwapBuffers(hdc);
|
|
}
|
|
|
|
// Clean-up:
|
|
if (opengl_context)
|
|
wglDeleteContext(opengl_context);
|
|
if (hdc)
|
|
ReleaseDC(hWnd, hdc);
|
|
if (hWnd)
|
|
DestroyWindow(hWnd);
|
|
|
|
return (int) msg.wParam;
|
|
}
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
switch (uMsg) {
|
|
case WM_QUIT:
|
|
case WM_CLOSE:
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
default:
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|