ぬの部屋(仮)
nu-no-he-ya
  •    1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • メモリデバイスコンテキストのカプセル化

    以前にも、以下の記事あたりで使ったのだが、メモリデバイスコンテキストをクラス化する話。

    MdcCanvas.hpp

    //! @file MdcCanvas.hpp
    //! @brief メモリデバイスコンテキストのカプセル化
    //! @date 2020/04/22 別コードから移植
    //! @date 2020/04/25 コメント整理
    
    #pragma once
    #include <cassert>
    #include <Windows.h>
    
    namespace szl {
      struct cbit24_t;
      struct cbit32_t;
    
      //! @brief メモリデバイスコンテキストのカプセル化
      //! @tparam PIXEL_BITS 1画素のデータ型。
    
      template<typename PIXEL_BITS>
      class CMdcCanvas
      {
        //CreateDIBSection , DDB , DIB 関連
    
        BITMAPINFO m_bmpInfo;   //!< CreateDIBSectionに渡す構造体
        LPDWORD m_lpPixel;      //!< 画素へのポインタ
        HBITMAP m_hBitmap;      //!< 作成したMDCのビットマップハンドル
        HDC m_hMemDC;           //!< 作成したMDCのハンドル
    
        int m_imagesizemax;     //!< 合計画素数(width*height)
        int m_width;            //!< 画像の幅(ピクセル,自然数)
        int m_height;           //!< 画像の高さ(ピクセル,自然数)
      public:
    
        //! @brief 新しい画像を作成。すでにあるなら現在のものを破棄して再作成
        //! @param [in] width 画像の幅。( > 0)
        //! @param [in] height 画像の高さ。負数の時は左下原点になる
        //! @param [in] hdc CreateCompatibleDCに渡すDCのハンドル。指定しない場合はCreateDCで自動作成
        //! @retval true 作成した
        //! @retval false 作成しなかった
        bool create_screen(int width, int height, HDC hdc=nullptr);
    
        //! @brief 現在使用している画像を削除。削除済みか作成されていないなら何もしない
        //! @return なし
        void delete_screen();
    
        //! @brief 仮想画面の幅を取得
        //! @return 画像幅(自然数)
        int get_width()const { return m_width; }
    
        //! @brief 仮想画面の高さを取得
        //! @return 画像高さ(自然数)
        int get_height()const { return m_height; }
    
    
        //! @brief メモリデバイスコンテキストを取得 (const)
        //! @return メモリデバイスコンテキスト
        const HDC get_mem_dc()const { return m_hMemDC; }
    
        //! @brief メモリデバイスコンテキストを取得
        //! @return メモリデバイスコンテキスト
        HDC get_mem_dc() { return m_hMemDC; }
    
        //! @brief BITMAPINFO構造体を取得
        //! @return BITMAPINFO構造体のコピー
        BITMAPINFO get_BITMAPINFO()const { return m_bmpInfo; }
    
        //! @brief HBITMAPを取得
        //! @return HBITMAPのコピー
        HBITMAP get_HBITMAP()const { return m_hBitmap; }
    
        //! @brief 書き込み用のメモリ領域へのアドレスを取得
        PIXEL_BITS* get_mem_pixel() { return reinterpret_cast<PIXEL_BITS * >(m_lpPixel); }
    
        //! @brief 書き込み用のメモリ領域へのアドレスを取得
        const PIXEL_BITS* get_mem_pixel()const { return reinterpret_cast<PIXEL_BITS*>(m_lpPixel); }
    
        //! @brief 画面に転送を行う
        //! @param [in] hdc 転送先のデバイスコンテキスト
        //! @param [in] rop 転送モード
        //! @return なし
        void bitblt_to(const HDC hdc,const DWORD rop = SRCCOPY)const;
    
        //! @brief 仮想画面が確保されているか
        //! @retval true 使用可能
        //! @retval false 使用不可
        bool is_valid()const { return (m_hBitmap == nullptr) ? false : true; }
    
        //! @brief 一次元配列として画素へアクセスする
        //! @param [in] index 要素番号
        //! @return 画素への参照
        //! @note indexが不正な場合assertする
        PIXEL_BITS& operator[](const int index) {
          assert(index >= 0 && index < m_imagesizemax);
          return get_mem_pixel()[index];
        }
    
        //! @brief 一次元配列として画素へアクセスする(const)
        //! @param [in] index 要素番号
        //! @return 画素への参照
        //! @note indexが不正な場合assertする
        const PIXEL_BITS& operator[](const int index)const {
          assert(index >= 0 && index < m_imagesizemax);
          return get_mem_pixel()[index];
        }
    
        //! @brief 二次元配列として画素へアクセスする
        //! @param [in] x X座標
        //! @param [in] y Y座標
        //! @return 画素への参照
        //! @note 座標が不正な場合assertする
        PIXEL_BITS& operator()(const int x, const int y) {
    
          assert(x >= 0 && y >= 0);
          assert(x < get_width() && y < get_height());
          assert((x + y * get_width()) < m_imagesizemax);
          return get_mem_pixel()[x + y * get_width()];
        }
    
        //! @brief 二次元配列として画素へアクセスする
        //! @param [in] x X座標
        //! @param [in] y Y座標
        //! @return 画素への参照
        //! @note 座標が不正な場合assertする
        const PIXEL_BITS& operator()(const int x, const int y)const {
          assert(x >= 0 && y >= 0);
          assert(x < get_width() && y < get_height());
          assert((x + y * get_width()) < m_imagesizemax);
          return get_mem_pixel()[x + y * get_width()];
    
        }
    
        //! @brief 初期化を行う
        CMdcCanvas(void);
        //! @brief 画像を破棄する
        ~CMdcCanvas(void);
      };
      //! @struct cbit24_t
      //! @brief 1画素 3Byte の場合のデータ型
      struct cbit24_t {
        unsigned char v[3];          //!< データ3Byte
    
        cbit24_t() {}
        cbit24_t(unsigned char r, unsigned char g, unsigned char b) :v{ b,g,r } {}
    
        unsigned char& r() { return v[2]; } //!< 赤を取得
        unsigned char& g() { return v[1]; } //!< 緑を取得
        unsigned char& b() { return v[0]; } //!< 青を取得
      };
    
      //! @struct cbit32_t
      //! @brief 1画素 4Byte の場合のデータ型
      struct cbit32_t {
        unsigned char v[4];          //!< データ3Byte
        cbit32_t() {}
        cbit32_t(unsigned char r, unsigned char g, unsigned char b, unsigned char u = 0) :v{ b,g,r,u } {}
    
        unsigned char& u() { return v[3]; } //!< 未使用領域を取得
        unsigned char& r() { return v[2]; } //!< 赤を取得
        unsigned char& g() { return v[1]; } //!< 緑を取得
        unsigned char& b() { return v[0]; } //!< 青を取得
      };
    
      //! @brief データ型のビット数を返す
      //! @tparam T データ型
      //! @return sizeofの8倍
      template<typename T>
      inline constexpr int bit_count() { return sizeof(T)*8; }
    
      //! @brief データ型のビット数を返す(自分定義3byte用)
      //! @return 24
      template<>inline constexpr int bit_count<cbit24_t>() { return 24; }
    
      //! @brief データ型のビット数を返す(自分定義4byte用)
      //! @return 32
      template<>inline constexpr int bit_count<cbit32_t>() { return 32; }
    
      template<typename PIXEL_BITS>
      CMdcCanvas<PIXEL_BITS>::CMdcCanvas(void)
      {
        m_hBitmap = nullptr;
        m_hMemDC = nullptr;
        m_lpPixel = nullptr;
        m_width = 0;
        m_height = 0;
        m_imagesizemax = 0;
      }
    
    
      template<typename PIXEL_BITS>
      CMdcCanvas<PIXEL_BITS>::~CMdcCanvas(void)
      {
        delete_screen();
      }
    
      template<typename PIXEL_BITS>
      bool CMdcCanvas<PIXEL_BITS>::create_screen(int width, int height, const HDC hdc) {
    
        //指定がおかしければ削除される
        if (width <= 0 || abs(height) <= 0) {
          delete_screen();
          return false;
        }
    
        //既にあるなら削除する
        if (is_valid()) {
          delete_screen();
        }
    
        m_width = width;
        m_height = abs(height);
    
    
    
        //デバイスコンテキストのハンドルの設定
        HDC hdcd;
        if (hdc == nullptr) {
          hdcd = CreateDCA("DISPLAY", 0, 0, 0);
        }
        else {
          hdcd = hdc;
        }
    
        //DIBの情報を設定する
        m_bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        m_bmpInfo.bmiHeader.biWidth = width;
        m_bmpInfo.bmiHeader.biHeight = -height; //-を指定しないと上下逆になる
        m_bmpInfo.bmiHeader.biPlanes = 1;
        m_bmpInfo.bmiHeader.biBitCount = bit_count<PIXEL_BITS>();
        m_bmpInfo.bmiHeader.biCompression = BI_RGB;
    
        m_hBitmap = CreateDIBSection(hdcd, &m_bmpInfo, DIB_RGB_COLORS, (void**)&m_lpPixel, nullptr, 0);
        m_hMemDC = CreateCompatibleDC(hdcd);
    
        if (hdc == nullptr) {
          DeleteDC(hdcd);
        }
    
        if (m_hBitmap == nullptr || m_hMemDC == nullptr) {
          delete_screen();
          return false;
        }
    
        SelectObject(m_hMemDC, m_hBitmap);
    
    
        m_imagesizemax = m_width * m_height;
    
        return true;
    
      }
    
      template<typename PIXEL_BITS>
      void CMdcCanvas<PIXEL_BITS>::delete_screen() {
        if (m_hBitmap == nullptr)
          return;
    
        DeleteDC(m_hMemDC);
        DeleteObject(m_hBitmap);
        m_lpPixel = nullptr;
        m_hBitmap = nullptr;
        m_hMemDC = nullptr;
    
        m_width = 0;
        m_height = 0;
        m_imagesizemax = 0;
      }
    
    
      template<typename PIXEL_BITS>
      void CMdcCanvas<PIXEL_BITS>::bitblt_to(const HDC hdc,const DWORD rop)const {
        BitBlt(hdc, 0, 0, get_width(), get_height(), m_hMemDC, 0, 0, rop);
      }
    
      using CMdcCanvas24 = CMdcCanvas<cbit24_t>;
      using CMdcCanvas32 = CMdcCanvas<cbit32_t>;
    
    }
    

    使い方

    #include<windows.h>
    
    #include "MdcCanvas.hpp"
    
    //メモリデバイスコンテキスト作成
    szl::CMdcCanvas24 vscr;
    
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
      HDC hdc;
      switch (msg) {
      case WM_SIZE:
        InvalidateRect(hwnd, nullptr, TRUE);
        break;
      case WM_PAINT:
        PAINTSTRUCT ps;
        hdc = BeginPaint(hwnd, &ps);
        vscr.bitblt_to(hdc);//画面に表示
        EndPaint(hwnd, &ps);
        break;
      case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR lpCmdLine, int nCmdShow) {
      HWND hwnd;
      WNDCLASS winc;
      MSG msg;
    
      winc.style = CS_HREDRAW | CS_VREDRAW;
      winc.lpfnWndProc = WndProc;
      winc.cbClsExtra = winc.cbWndExtra = 0;
      winc.hInstance = hInstance;
      winc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      winc.hCursor = LoadCursor(NULL, IDC_ARROW);
      winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      winc.lpszMenuName = NULL;
      winc.lpszClassName = TEXT("DC_TEST");
    
      if (!RegisterClass(&winc)) return 0;
    
      hwnd = CreateWindow(
        TEXT("DC_TEST"), TEXT("mem dc test"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        300, 300,
        NULL, NULL,
        hInstance, NULL
      );
    
    
      //画像作成
      HDC dc = GetDC(hwnd);
      vscr.create_screen(200, 100,dc);
      ReleaseDC(hwnd, dc);
    
    
      int i = 0;
    
      //メモリに直接アクセス
      for (int i = 0; i < 200 * 100; i++) {
        vscr.get_mem_pixel()[i] = szl::cbit24_t(100, 255, 100);
      }
    
      //GDIオブジェクトとして扱う
      HPEN hp = CreatePen(PS_SOLID, 5, RGB(255, 0, 0));
      HPEN oldp = (HPEN)SelectObject(vscr.get_mem_dc(), hp);
      MoveToEx(vscr.get_mem_dc(), -10, -10,nullptr);
      LineTo(vscr.get_mem_dc(), 50, 80);
      SelectObject(vscr.get_mem_dc(), oldp);
      DeleteObject(hp);
    
      //二次元配列の形でアクセス
      vscr(0, 0) = szl::cbit24_t(255, 0, 0);
      vscr(0, 1) = szl::cbit24_t(255, 0, 0);
      vscr(0, 2) = szl::cbit24_t(0, 255, 0);
      vscr(0, 3) = szl::cbit24_t(0, 0, 255);
    
      if (hwnd == NULL) return 0;
    
      while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
      return msg.wParam;
    }
    

    雑談

    世の中にはたくさんの「簡単に使えるようにクラスにしてまとめました」があるが、そのほとんどは使い物にならないと私は考えている。もちろん自分で作ったものも含めて。

    というのも、クラス化というのはある程度の目的や明確な用途があって初めて効果を発揮するものなので、普段自分が使う部分だけが使いやすくなるように作って使いやすくなったように見えてもそれは自分にとってだけなのだ。むしろ提示されたほうは学習コストが無駄にかかる。