win32原生API實現OpenGL例子(無glew,glut等第三方依賴庫)

話不多說,直接上代碼:

#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操作無效。

發佈了25 篇原創文章 · 獲贊 29 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章