基于OpenGL编写一个简易的2D渲染框架-01 创建窗口

最近正在学习OpenGL,我认为学习的最快方法就是做一个小项目了。

如果对OpenGL感兴趣的话,这里推荐一个很好的学习网站 https://learnopengl-cn.github.io/

我用的是 vs2013,使用C++语言编写项目。这个小项目叫Simple2D,意味着简易的2D框架。最终的目的是可以渲染几何图形和图片,最后尝试加上一个2D粒子系统和Box2D物理引擎,并编译一个简单的游戏。

 

第一步,就是创建一个Win32项目。

接下来,生成一个窗口。编写一个RenderWindow类,用于创建窗口。头文件很简单

 1 #pragma once
 2 #include "Common.h"
 3 #include <Windows.h>
 4 #include <string>
 5 
 6 namespace Simple2D
 7 {
 8     class DLL_export RenderWindow
 9     {
10     public:
11         RenderWindow(int width, int height, const char* title = "Simple2D");
12         ~RenderWindow();
13 
14         void createWindow(int width, int height, const char* title);
15         void setClientSize(int width, int height);
16 
17         static LRESULT WINAPI static_window_proc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
18 
19     private:
20         HWND hwnd;
21     };
22 }

下面是它的实现

 1 #include "RenderWindow.h"
 2 #include <exception>
 3 
 4 #define CLASS_NAME "Simple2DApplication"
 5 
 6 namespace Simple2D
 7 {
 8     RenderWindow::RenderWindow(int width, int height, const char* title)
 9     {
10         this->createWindow(width, height, title);
11     }
12 
13     RenderWindow::~RenderWindow()
14     {
15 
16     }
17 
18     void RenderWindow::createWindow(int width, int height, const char* title)
19     {
20         WNDCLASS wndclass;
21         memset(&wndclass, 0, sizeof(wndclass));
22 
23         wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
24         wndclass.lpfnWndProc = (WNDPROC)RenderWindow::static_window_proc;
25         wndclass.cbClsExtra = 0;
26         wndclass.cbWndExtra = 0;
27         wndclass.hInstance = ( HINSTANCE ) GetModuleHandle(0);
28         wndclass.hIcon = 0;
29         wndclass.hCursor = 0;
30         wndclass.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
31         wndclass.lpszMenuName = 0;
32         wndclass.lpszClassName = TEXT(CLASS_NAME);
33         RegisterClass(&wndclass);
34 
35         /* 创建窗口 */
36         CreateWindowA(CLASS_NAME, title, WS_OVERLAPPEDWINDOW, 100, 100, width, height,
37             NULL, NULL, ( HINSTANCE ) GetModuleHandle(0), this);
38 
39         if ( hwnd == NULL ) throw std::exception("Unable to create window");
40 
41         /* 显示窗口 */
42         ShowWindow(hwnd, SW_SHOWNA);
43         setClientSize(width, height);
44     }
45 
46     void RenderWindow::setClientSize(int width, int height)
47     {
48         /* 设置客户区大小为 width, height */
49         RECT rectProgram, rectClient;
50         GetWindowRect(hwnd, &rectProgram);
51         GetClientRect(hwnd, &rectClient);
52 
53         int borderw = rectProgram.right - rectProgram.left - (rectClient.right - rectClient.left);
54         int borderh = rectProgram.bottom - rectProgram.top - (rectClient.bottom - rectClient.top);
55 
56         borderw += width;
57         borderh += height;
58 
59         int showToScreenX = GetSystemMetrics(SM_CXSCREEN) / 2 - borderw / 2;
60         int showToScreenY = GetSystemMetrics(SM_CYSCREEN) / 2 - borderh / 2;
61 
62         MoveWindow(hwnd, showToScreenX, showToScreenY, borderw, borderh, false);
63     }
64 
65     LRESULT WINAPI RenderWindow::static_window_proc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
66     {
67         RenderWindow* self = nullptr;
68         if ( msg == WM_CREATE ) {
69             LPCREATESTRUCT create_struct = ( LPCREATESTRUCT ) lParam;
70             self = ( RenderWindow* ) create_struct->lpCreateParams;
71             SetWindowLongPtr(wnd, GWLP_USERDATA, ( LONG_PTR ) self);
72             self->hwnd = wnd;
73         }
74         else {
75             self = ( RenderWindow* ) GetWindowLongPtr(wnd, GWLP_USERDATA);
76         }
77 
78         switch ( msg ) {
79         case WM_CLOSE:
80             PostQuitMessage(0);
81             break;
82         case WM_DESTROY:
83             PostQuitMessage(0);
84             break;
85         case WM_PAINT:
86             RECT rect;
87             if ( GetUpdateRect(wnd, &rect, FALSE) ) {
88                 ValidateRect(wnd, &rect);
89             }
90             break;
91         }
92         return DefWindowProc(wnd, msg, wParam, lParam);
93     }
94 }

主要是注册窗口类,创建窗口和显示窗口。有一点需要注意的是,我这里的窗口大小并不是真正的窗口大小,而是客户区的大小,在 函数 setClientSize 中可以看出,我重新计算了窗口的真正大小。

 

最后是主函数

#pragma once
#include <Windows.h>
#include "RenderWindow.h"

using namespace Simple2D;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    RenderWindow window(DEFAULT_WIN_W, DEFAULT_WIN_H);

    MSG msg = { 0 };
    while ( msg.message != WM_QUIT ) {
        if ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) ) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else {
            // TODO:
        }
    }

    return 0;
}

只是创建了对象 RenderWindow,和消息循环。

 

运行后,得到下面的结果

按照我推荐的那个教程,你也可以使用 GLFW 库来创建一个窗口,这种方法更简单。有兴趣的可以尝试一下。

这里是源码地址:https://files.cnblogs.com/files/ForEmail5/Simple2D-01.rar

 

posted @ 2017-04-29 20:02  为了邮箱5  阅读(1346)  评论(1编辑  收藏  举报