zoukankan      html  css  js  c++  java
  • 基于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 库来创建一个窗口,这种方法更简单。有兴趣的可以尝试一下。

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

  • 相关阅读:
    多重背包POJ1276不要求恰好装满 poj1014多重背包恰好装满
    哈理工1053完全背包
    求最小公倍数与最大公约数的函数
    Bus Pass ZOJ 2913 BFS 最大中取最小的
    POJ 3624 charm bracelet 01背包 不要求装满
    HavelHakimi定理(判断一个序列是否可图)
    z0j1008Gnome Tetravex
    ZOJ 1136 Multiple BFS 取模 POJ 1465
    01背包 擎天柱 恰好装满 zjut(浙江工业大学OJ) 1355
    zoj 2412 水田灌溉,求连通分支个数
  • 原文地址:https://www.cnblogs.com/ForEmail5/p/6786098.html
Copyright © 2011-2022 走看看