步骤:
1、创建windows窗口,得到窗口句柄hwnd
2、获取该窗口的设备环境hDC(当然也可以获取其他的设备环境,但我们一般是在创建的窗口上绘制)
3、创建OpenGL绘制环境RC,这个只能从hDC创建
4、将hDC和RC绑定到当前的线程
注:RC表示OpenGL的绘制环境,所有的OpenGL命令都会在RC这个绘制环境中作用,所以必须在RC绑定到当前线程之后才能调用OpenGL命令,否则运行出错,内存访问错误。
一般的笔刷绘制,在hDC下即可。
封装的窗口类如下:
GLWindow.h
#pragma once #include <windows.h> #include <GL/glew.h> #include <iostream> class GLContext { public: GLContext(); ~GLContext(); void Setup(HWND,HDC); void SetupPixelFormat(HDC); private: HWND hWnd; HDC hDC; HGLRC hRC; int format; }; GLContext::GLContext() { this->hWnd = 0; this->hDC = 0; this->hRC = 0; this->format = 0; } GLContext::~GLContext() { } void GLContext::SetupPixelFormat(HDC hDC) { int pixelFormat; PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size 1, // version PFD_SUPPORT_OPENGL | // OpenGL window PFD_DRAW_TO_WINDOW | // render to window PFD_DOUBLEBUFFER, // support double-buffering PFD_TYPE_RGBA, // color type 32, // prefered color depth 0, 0, 0, 0, 0, 0, // color bits (ignored) 0, // no alpha buffer 0, // alpha bits (ignored) 0, // no accumulation buffer 0, 0, 0, 0, // accum bits (ignored) 16, // depth buffer 0, // no stencil buffer 0, // no auxiliary buffers PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0, // no layer, visible, damage masks }; pixelFormat = ChoosePixelFormat(hDC, &pfd); SetPixelFormat(hDC, pixelFormat, &pfd); } void GLContext::Setup(HWND hwnd, HDC hdc) { this->hWnd = hwnd; this->hDC = hdc; SetupPixelFormat(hDC); hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC); //initialize glew glewExperimental = GL_TRUE; glewInit(); if (AllocConsole()) { freopen("CONOUT$", "w+t", stdout); freopen("CONOUT$", "w+t", stderr); const GLubyte* Devise = glGetString(GL_RENDERER); //返回一个渲染器标识符,通常是个硬件平台 const GLubyte* str = glGetString(GL_VERSION); printf("OpenGL实现的版本号:%s ", str); printf("硬件平台:%s ", Devise); } } LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); class GLWindow { public: GLWindow(); ~GLWindow(); void Setup(HINSTANCE, HINSTANCE, LPSTR, int); //LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void RegisterDisplayFunc(void (*display)()) { this->Display = display; } void Run(); private: void(*Display)(); private: bool exiting = false; long windowWidth = 800; long windowHeight = 600; long windowBits = 64; bool fullscreen = false; WNDCLASSEX windowClass; // window class HWND hwnd; // window handle HDC hDC; MSG msg; // message DWORD dwExStyle; // Window Extended Style DWORD dwStyle; // Window Style RECT windowRect; GLContext glContext; }; GLWindow::GLWindow() {} GLWindow::~GLWindow() {} void GLWindow::Setup(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { windowRect.left = (long)0; // Set Left Value To 0 windowRect.right = (long)windowWidth; // Set Right Value To Requested Width windowRect.top = (long)0; // Set Top Value To 0 windowRect.bottom = (long)windowHeight; // Set Bottom Value To Requested Height // fill out the window class structure windowClass.cbSize = sizeof(WNDCLASSEX); windowClass.style = CS_HREDRAW | CS_VREDRAW; windowClass.lpfnWndProc = MainWindowProc; //当窗体触发任何一个事件时,便会调用该函数 windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = hInstance; windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); // default icon windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // default arrow windowClass.hbrBackground = NULL; // don't need background windowClass.lpszMenuName = NULL; // no menu windowClass.lpszClassName = L"Windows API"; windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // windows logo small icon // register the windows class if (!RegisterClassEx(&windowClass)) { puts("Register Class Failed"); } dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style dwStyle = WS_OVERLAPPEDWINDOW; // Windows Style AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size // class registered, so now create our window hwnd = CreateWindowEx(NULL, // extended style L"Windows API", // class name L"OpenGL", // app name dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, // x,y coordinate windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, // width, height NULL, // handle to parent NULL, // handle to menu hInstance, // application instance NULL); // no extra params ShowWindow(hwnd, SW_SHOW); // display the window UpdateWindow(hwnd); // update the window hDC = GetDC(hwnd); glContext.Setup(hwnd,hDC); } LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { int height, width; // dispatch messages switch (uMsg) { case WM_CREATE: // window creation break; case WM_DESTROY: // window destroy case WM_QUIT: CloseWindow(hWnd); break; case WM_CLOSE: // windows is closing // deselect rendering context and delete it //wglMakeCurrent(hDC, NULL); //wglDeleteContext(hRC); // send WM_QUIT to message queue PostQuitMessage(0); break; case WM_SIZE: height = HIWORD(lParam); // retrieve width and height width = LOWORD(lParam); break; case WM_ACTIVATEAPP: // activate app break; case WM_PAINT: // paint PAINTSTRUCT ps; BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); break; case WM_LBUTTONDOWN: // left mouse button break; case WM_RBUTTONDOWN: // right mouse button break; case WM_MOUSEMOVE: // mouse movement break; case WM_LBUTTONUP: // left button release break; case WM_RBUTTONUP: // right button release break; case WM_KEYUP: break; case WM_KEYDOWN: int fwKeys; LPARAM keyData; fwKeys = (int)wParam; // virtual-key code keyData = lParam; // key data switch (fwKeys) { case VK_ESCAPE: PostQuitMessage(0); break; default: break; } break; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } void GLWindow::Run() { while (true) { (*Display)(); SwapBuffers(hDC); while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if (!GetMessage(&msg, NULL, 0, 0)) { exiting = true; break; } TranslateMessage(&msg); DispatchMessage(&msg); } } }
主函数调用代码示例:
#include <Windows.h> #include <cameras/phc.h> #include "shader.h" #include "Cube.h" #include "GLWindow.h" redips::PhC phc; GLWindow window; Shader* shader; Cube* cube; void Display() { cube->Draw(*shader, phc); } void Initialize(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { phc.lookAt(redips::float3(0, 0, 200), redips::float3(0, 0, 0), redips::float3(0, 1, 0)); window.Setup(hInstance, hPrevInstance, lpCmdLine, nShowCmd); window.RegisterDisplayFunc(Display); shader = new Shader("./joint.vert", "./joint.frag"); cube = new Cube(); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { Initialize(hInstance, hPrevInstance, lpCmdLine, nShowCmd); window.Run(); return 1; }
运行: