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

  • 相关阅读:
    Linux基础知识第九讲,linux中的解压缩,以及软件安装命令
    Linux基础知识第八讲,系统相关操作命令
    Linux基础知识第七讲,用户权限以及用户操作命令
    Linux基础知识第六讲,远程管理ssh操作
    【Android】21.4 图片动画缩放示例
    【Android】21.3 动画
    【Android】21.2 2D图形图像处理(Canvas和Paint)
    【Android】21.1 画板资源
    【Android】第21章 2D图形和动画
    【Android】Java堆栈溢出的解决办法
  • 原文地址:https://www.cnblogs.com/ForEmail5/p/6786098.html
Copyright © 2011-2022 走看看