話不多說,直接上代碼:
#include<Windows.h>
#include<GL/GL.h>
#pragma comment(lib,"opengl32.lib")
//註冊win32窗口類
BOOL win32_regist_class(const char* class_name)
{
WNDCLASSEXA cs =
{
sizeof(WNDCLASSEXA),
CS_HREDRAW | CS_VREDRAW,
[](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)->LRESULT
{
switch (msg)
{
case WM_NCCREATE:
{
SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCTA)lparam)->lpCreateParams);
break;
};
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
}
case WM_ERASEBKGND://阻止窗口重繪,不然當窗口從邊界移回來時會看到背景色
{
return TRUE;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
break;
}
return DefWindowProcA(hwnd, msg, wparam, lparam);
},
0,
0,
(HINSTANCE)GetModuleHandleA(nullptr),
nullptr,
LoadCursorA(nullptr,IDC_ARROW),
(HBRUSH)COLOR_WINDOW,
nullptr,
class_name,
nullptr
};
return RegisterClassExA(&cs);
}
//創建win32窗口
HWND win32_create(const char*class_name,const char*window_name,int x, int y, int width, int height)
{
return CreateWindowExA(0, class_name,window_name, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
x, y, width, height,
nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
}
//獲取可用於OpenGL繪製的DC
HDC win32_get_gl_dc(HWND hwnd)
{
PIXELFORMATDESCRIPTOR pfd = {};
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
auto hdc = GetDC(hwnd);
auto pixelFormat = ChoosePixelFormat(hdc, &pfd);
if (!pixelFormat)
{
ReleaseDC(hwnd, hdc);
return nullptr;
}
if (!SetPixelFormat(hdc, pixelFormat, &pfd))
{
ReleaseDC(hwnd, hdc);
return nullptr;
}
return hdc;
}
//處理win32消息
BOOL win32_peek_message(HWND hwnd)
{
MSG msg;
if (PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return FALSE;
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
return TRUE;
}
//創建OpenGL API
HGLRC gl_create(HDC hdc)
{
auto hglrc = wglCreateContext(hdc);
if (!hglrc)
return nullptr;
if (!wglMakeCurrent(hdc, hglrc))
return nullptr;
////////獲取高版本API(glew的最主要功能就是這是一步)
/*
在這個裏獲取會用到的opengl api,這些API名稱可以去opengl官網查詢
因爲需要的功能不復雜,不需要使用着色器,GL1.0版本的API足夠用了。
所以這裏並沒有獲取所有高版本的API,只獲取了一個glCreateShader作爲例子。
*/
auto glCreateShader=(GLuint(__stdcall*)(GLenum type))wglGetProcAddress("glCreateShader");
////////獲取高版本API結束
return hglrc;
}
//渲染
void render(HWND hwnd, HDC hdc, HGLRC hglrc)
{
RECT rc;
GetClientRect(hwnd, &rc);
wglMakeCurrent(hdc, hglrc);//關聯gl的DC到窗口的hdc。如果是單DC,只需關聯一次即可
glViewport(0, 0, rc.right, rc.bottom);//設置視口
glClearColor(0.4f, 0.5f, 0.4f, 0);//設置清屏時的顏色
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清屏。這裏清掉顏色緩衝區與深度緩衝區
////////////以下內容爲1.0版本繪製方法,高版本的不建議這樣繪製了,儘量使用glDraw*系列函數以提高性能
//設置點
glBegin(GL_TRIANGLE_STRIP); //以畫線方式繪製,
glColor3f(1, 0, 0); glVertex2f(0.0f, 0.0f);//中心端點,爲紅色
glColor3f(0, 1, 0); glVertex2f(0.5f, 0.5f);//到左上角中點端點,爲綠色
glColor3f(0, 0, 1); glVertex2f(0.0f, 0.5f);//到上方中點端點,爲藍色
glEnd();
//glDrawArrays(GL_LINES, 0, 2);//經過測試,1.0版本不需要調用此函數
}
int main(int argc, const char* argv[])
{
win32_regist_class("test");
auto hwnd = win32_create("test", "test", 100, 100, 500, 400);
auto hdc = win32_get_gl_dc(hwnd);
auto hglrc = gl_create(hdc);
while (true)
{
if(win32_peek_message(nullptr)==FALSE)
break;
render(hwnd, hdc, hglrc);
SwapBuffers(wglGetCurrentDC());//翻轉緩衝區(因爲使用了雙緩衝,必須要翻轉才能看到繪製結果)
}
}
整個代碼約140行,不算多。這是上次QQ羣裏一個人問我之後我改了之前的代碼寫出來的,邏輯比之前強很多,個人感覺優勢在於不再需要亂七八糟的第三方庫,可以作爲學習用,在自己獲取高版本GL的API後也可以簡單取代glut。
主要部分是win32_get_gl_dc(HWND hwnd)這個函數。這個函數執行成功了就可以繼續後續的OpenGL操作,不然的話就會出現GL上下文創建失敗的情況,導致後續的OpenGL操作無效。