ぬの部屋(仮)
nu-no-he-ya
  • 1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       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     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         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     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       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
           
  • VC++でcrtdbg.hでメモリリークを検出

    #include <iostream>
    
    // メモリリークを検出した位置を表示するためのマクロ
    #define _CRTDBG_MAP_ALLOC
    
    // メモリリークの検出
    #include <crtdbg.h>
    
    // メモリリークしたメモリのnewした場所のファイル名と行数を表示する
    // #define _CRTDBG_MAP_ALLOC で動く機能のはずなのだがなぜか機能しないので自分で定義する
    #define new ::new(_NORMAL_BLOCK, __FILE__, __LINE__)
    
    
    
    class Dummy
    {
    public:
    
    	char* myleak() {
            char* p = new char[3] {0, 0, 0}; // メモリリークしている (19行目)
            return p;
    	}
    
    	void mysafety() {
            int* q = new int[3] {1, 1, 1}; // メモリリークしていない (24行目)
            printf("%d %d %d\n", q[0], q[1], q[2]);
            delete [] q;
    	}
    
        Dummy() {}
        ~Dummy() {}
    };
    

    int main()
    {
        // アプリケーション終了時に_CrtDumpMemoryLeaks()が呼ばれるように指示
        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
        
        Dummy d;
        std::cout << "Hello World!\n";
        char* c = d.myleak();
        d.mysafety();
        
        // 出力内容と出力先
        // https://learn.microsoft.com/ja-jp/cpp/c-runtime-library/reference/crtsetreportmode?view=msvc-170
        // _CRT_WARN          ... 警告、メッセージ、およびすぐに注意する必要のない情報。
        // _CRTDBG_MODE_DEBUG ... デバッガーの出力ウィンドウにメッセージを書き込みます。
        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
        
        // メモリリークの情報を出力
        // この関数は、呼び出された時点で解放されていないメモリを全て検知する。
        // アプリケーション終了時でのリークを検出したいならここで書かないで
        // _CrtSetDbgFlagでプログラムが終了したときに自動的に呼び出されるように指示したほうがいい。
        // _CrtDumpMemoryLeaks();
        
        return 0;
    }
    

    出力

    _CrtSetReportMode関数で_CRTDBG_MODE_DEBUGを指定しているので、デバッグウィンドウに以下の出力がされる。

    ファイル名 , newした行番号 , newしたメモリサイズ がそれぞれ出力される。

    Detected memory leaks!
    Dumping objects ->
    C:\myproj\ConsoleApplication5\ConsoleApplication5.cpp(19) : {161} normal block at 0x0000029DA8896EA0, 3 bytes long.
     Data: <   > 00 00 00
    Object dump complete.
    プログラム '[26332] ConsoleApplication5.exe' はコード 0 (0x0) で終了しました。

    参考

    癖をまとめてくれているサイト。

    プログラマの友

    http://www7b.biglobe.ne.jp/~robe/pf/pf008.html

    このcrtdbg.hによるメモリリーク検出、プロジェクトの規模が大きくなってくるとかなり気を遣わなければいけないらしい。

    閑古鳥

    WordPressの管理画面の投稿一覧のカラムが狭すぎる問題を解決

    WordPressの管理画面の投稿一覧が、いつの間にかタイトルなどのカラムがとても狭くなってしまって困った。これを解決する方法を探した。functions.phpでadmin_headをadd_actionすればよいらしい。

    functions.phpへ追記

    column-cbはチェックボックス部分の幅。一応指定している。

    title(タイトル),author(投稿者),categories(カテゴリ), ... をそれぞれ指定。

    .postsは投稿一覧、.pagesは固定ページ一覧。

    <?php
    /****************************************/
    /* 投稿・固定ページ一覧のカラム幅指定 */
    function column_title_width(){
    
    echo '
    
    <style>
      .posts .column-cb { width: 40px; } .pages .column-cb { width: 40px;} .posts .column-title { width: 300px; } .pages .column-title { width: 300px; } .posts .column-author { width: 50px; } .pages .column-author { width: 50px; } .posts .column-categories { width: 100px; } .pages .column-categories { width: 100px; } .posts .column-tags { width: 150px; } .pages .column-tags { width: 150px; } </style>
    ';
    
    }
    
    add_action('admin_head','column_title_width');
    /****************************************/
    
    ?>
    

    適用結果

    参考

    https://laptopreneur.net/wordpress%E7%AE%A1%E7%90%86%E7%94%BB%E9%9D%A2-%E3%82%AB%E3%83%A9%E3%83%A0%E5%B9%85%E5%A4%89%E6%9B%B4/

    VC++のプロジェクトにCUDAの.cuファイルが混在しているものをビルドする

    VC++で、.cpp と .cuファイルが混在したプロジェクトのビルド方法。

    1.ビルドのカスタマイズ

    プロジェクトを右クリックして、「ビルドの依存関係」→「ビルドのカスタマイズ」を選択。

    使用できるビルド カスタマイズ ファイルの中から、 CUDA 12.1 をチェックして OK をクリックする。

     

    2..cuファイルをビルドに含める

    .cuファイルを右クリック → プロパティ → プロパティページ を開き、「全般」から以下を設定

    ・ビルドから除外 → いいえ

    ・項目の種類 → CUDA C/C++

    サンプルコード

    source.cpp

    #include <windows.h>
    #include <memory>
    
    #include "mycuda.cuh"
    
    #pragma warning(disable:4996)
    
    void pnmP3_Write(const char* const fname, const int width, const int height, const unsigned char* const p);
    
    static const int N = 500;//作成画像 N × N
    
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    
      static std::unique_ptr<unsigned char[]> p_cpu;
    
      switch (msg) {
      case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
      case WM_CREATE:
        p_cpu.reset(new unsigned char[N * N * 3]);
        call_mycuda(N, p_cpu.get());
    
        return 0;
      case WM_PAINT:
      {
        // dc設定
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        for(int x=0;x<N;x++)
          for (int y = 0; y < N; y++) {
            size_t pos = N * y + x;//二次元座標を一次元座標に
            SetPixel(hdc, x, y,
              RGB(
                p_cpu[pos * 3 + 0],
                p_cpu[pos * 3 + 1],
                p_cpu[pos * 3 + 2]
              )
            );
          }
        EndPaint(hwnd, &ps);
      }
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR lpCmdLine, int nCmdShow) {
      HWND hwnd;
      MSG msg;
      WNDCLASS winc;
    
      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("SZL-WINDOW");
    
      if (!RegisterClass(&winc)) return -1;
    
      hwnd = CreateWindow(
        TEXT("SZL-WINDOW"), TEXT("mywindow"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        N+100, N+100,
        NULL, NULL, hInstance, NULL
      );
    
      if (hwnd == NULL) return -1;
    
      while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
      return msg.wParam;
    }
    
    /////////////////////////////////////////////
    //画像ファイル書き出し/////////////////////////
    //! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む
    //! @param [in] fname ファイル名
    //! @param [in] width 画像の幅
    //! @param [in] height 画像の高さ
    //! @param [in] p 画像のメモリへのアドレス
    //! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
    void pnmP3_Write(const char* const fname, const int width, const int height, const unsigned char* const p) { // PPM ASCII
    
      FILE* fp = fopen(fname, "wb");
      fprintf(fp, "P3\n%d %d\n%d\n", width, height, 255);
    
      size_t k = 0;
      for (size_t i = 0; i < (size_t)height; i++) {
        for (size_t j = 0; j < (size_t)width; j++) {
          fprintf(fp, "%d %d %d ", p[k * 3 + 0], p[k * 3 + 1], p[k * 3 + 2]);
          k++;
        }
        fprintf(fp, "\n");
      }
    
      fclose(fp);
    }
    

    mycuda.cuh

    #include <stdio.h>
    #include <cstring>
    
    #include <cuda_runtime.h>
    
    void call_mycuda(const int N, unsigned char* p_cpu);
    
    
    ///////////////////////////////////////////////
    // GPU側 ////////////////////////////////////// 
    __global__ void gradation(unsigned char* c, const int N);
    

    mycuda.cu

    #include "mycuda.cuh"
    
    #include <device_launch_parameters.h>
    
    #pragma comment(lib,"cudart.lib")
    #pragma comment(lib,"cuda.lib")
    
    
    void call_mycuda(const int N, unsigned char* p_cpu) {
      //作成画像 N × N × 3
    
      //16×16の領域に分けて計算する
      dim3 block(16, 16);
    
      //グリッド数
      dim3 grid(N / 16 + 1, N / 16 + 1);
    
      unsigned char* p_gpu;//GPU側メモリ確保
      cudaMalloc((void**)&p_gpu, N * N * 3);
      gradation << <grid, block >> > (p_gpu, N);
    
      //GPU→CPU側へメモリコピー
      cudaMemcpy(p_cpu, p_gpu, N * N * 3, cudaMemcpyDeviceToHost);
      cudaFree(p_gpu);
    
    }
    
    __global__ void gradation(unsigned char* c, const int N) {
    
        //アクセス法
        //このスレッドが担当する画素の位置を二次元座標で求める
        size_t xpos = blockIdx.x * blockDim.x + threadIdx.x;
        size_t ypos = blockIdx.y * blockDim.y + threadIdx.y;
    
        if (xpos < N && ypos < N) {
            size_t pos = N * ypos + xpos;//二次元座標を一次元座標に
            float R = ypos / (float)N;
            float G = (N - ypos) / (float)N;
            float B = xpos / (float)N;
            c[pos * 3 + 0] = R * 255;//0~255にして色書き込み
            c[pos * 3 + 1] = G * 255;
            c[pos * 3 + 2] = B * 255;
        }
    }
    

    実行結果

    参考

    Unreal Engine 5 でレベルを追加して切り替える

    レベルとは(誤解を恐れずに)端的にいうとマップのこと。

    レベルは保存しなければ操作できないので、まず作成・保存方法を確認する。

    1.マップを新規追加・保存

    レベルの新規追加

    レベルを追加するには [新規レベル] → [新規レベル] から行う。

    レベルを保存

    レベルを保存するには、[ファイル] → [現行レベルを保存] から行う。名前を付けると、コンテンツブラウザに登録される。

    2.レベルブループリントを編集

    上記方法でレベルを二つ作成して保存(My-Map-1 、 My-Map-2)したら、

    1.My-Map-1 をダブルクリックして開く

    2.レベルブループリントを開く

    3.ノードを設定

    Keyboard F に Open Level を接続し、Level に先ほど作成した My-Map-2を指定する。

    これでMy-Map-1を実行し、Fを押すとMy-Map-2へ切り替わる。

    vtkProgressObserverをつかって進捗を表示

    VTK9.3で、PLY読み込みなどを行う際に進捗状況を%表示する方法。

    vtkProgressObserverを指定するSetProgressObserverメンバ関数はvtkAlgorithmで定義されているので、vtkAlgorithmを継承した処理でないとこの方法は使えない

    1.vtkProgressObserverを継承したMyProgressObserverを定義

    2.UpdateProgressをオーバーライドし、amountから進捗を取得

    3.MyProgressObserverのインスタンスを作成

    4.vtkPLYReaderなどのインスタンスを作成

    5.SetProgressObserverにオブザーバーのポインタを与える

    // 進捗管理用
    #include <vtkProgressObserver.h>
    
    // PLYファイル読み込み用
    #include <vtkPLYReader.h>
    
    // 読み込めているか確認用
    #include <vtkPointData.h>
    
    
    //////////////////////////////////////////////////
    // 進捗管理のためにvtkProgressObserverを継承したクラスを作成
    class MyProgressObserver : public vtkProgressObserver {
    public:
    
      // UpdateProgressをオーバーライド
      virtual void UpdateProgress(double amount)override {
        // 進捗を表示
        printf("== %d\n", int(amount*100) );// amountは進捗状況を0.0~1.0で表現
      }
    };
    
    void myload() {
    
      const char* filename = "C:\\test\\mill.ply";
    
      ////////////////////////////////////////////////////////////
    
      // 進捗管理用のオブザーバを作成
      vtkSmartPointer<MyProgressObserver> observer = vtkSmartPointer<MyProgressObserver>(new MyProgressObserver);
    
      ////////////////////////////////////////////////////////////
      // PLYファイルを読み込むオブジェクト作成
      vtkSmartPointer<vtkPLYReader> plyReader = vtkSmartPointer<vtkPLYReader>::New();
      plyReader->SetProgressObserver(observer);// オブザーバを設定
      plyReader->SetFileName(filename);
      plyReader->Update();
      ////////////////////////////////////////////////////////////
    
      // 読み込んだデータを取得
      vtkSmartPointer<vtkPolyData> polyData = plyReader->GetOutput();
      vtkSmartPointer<vtkPoints> points = polyData->GetPoints();
    
      if (points == nullptr) {
        return;
      }
      for (vtkIdType i = 0; i < points->GetNumberOfPoints(); i++)
      {
        double p[3];
        points->GetPoint(i, p);
        printf("%lf %lf %lf\n", p[0], p[1], p[2]);
      }
    
    }
    

    Unreal Engine 5 で Landscapeを追加してみる

    Landscapeは地形。現在のレベルに新に地形を追加する。

    新規Landscape追加

    選択モード → ランドスケープ からランドスケープモードへ移行する

    ランドスケープの設定をして「作成」をクリック。あまり大きくしすぎると編集が大変になるので、コンポーネント数を1x2にしておく。

    スカルプトの要領で、マウスドラッグで地形を作れる。ただし作れるのは高低差だけなので、洞窟のようなものはできない。

    実行すると、地形の上を歩くことができるようになっている。

    MFCでCA2Wを使ってchar*文字列をwchar_t*文字列に変換する

    MFCでchar*からwchar_t*へ変換する話。この処理はMultiByteToWideChar関数で行えるが、MFCであれば、CA2Wという便利クラスでラップされているのでこれを使える。

    諸事情によりマルチバイト文字セットでプロジェクトを作らなければいけないが、使用するライブラリがconst wchar_t*を要求するという状況に遭遇して調べた。

    CA2W

    void CChildView::OnPaint() 
    {
      CPaintDC dc(this);
    
      const char *szText = "テキスト";
      wchar_t* wideText = ATL::CA2W(szText);
    
      ::TextOutW(dc.GetSafeHdc(), 0, 0, wideText,wcslen(wideText));
    
    }
    

    このCA2Wというクラスが何をやっているかというと、

    1.CA2Wはコンストラクタにchar*が渡される
    2.内部でwchar_t*のバッファを128byte確保
    3.MultiByteToWideCharを呼び出してバッファへ格納(バッファサイズはテンプレート引数で指定可能)
    4.出来上がった結果はoperator LPWSTR()によって暗黙キャストされて返却

    普通、式内で作られたCA2Wオブジェクトは式が終わると同時に解放されるが、C++は一時オブジェクトが参照されている場合、現在のスコープの終わりまでライフタイムが延長されるという機能があり、これによってCA2WはwideTextと同じ長さの寿命を持てる。

    MultiByteToWideCharを直接使う場合

    下記のようになる。delete[]し忘れが怖い。CA2Wを使ったほうがいい。

    void CChildView::OnPaint() 
    {
      CPaintDC dc(this);
    
      const char *szText = "サンプルテキスト";
    
      wchar_t* wideText = new wchar_t[128];
    
    MultiByteToWideChar( CP_ACP, // コードページ。ANSI 0, // フラグ。0でいい szText, // 変換したい文字列 -1, // 文字列の長さ。-1でnull終端で自動計算 wideText,// 変換後の文字列を格納するバッファ 128 // 変換後の文字列を格納するバッファのサイズ ); ::TextOutW(dc.GetSafeHdc(), 0, 0, wideText,wcslen(wideText)); delete [] wideText; // 解放を忘れずに }

    その他

    char* →wchar_t* の CA2W の他に、
    TCHAR → wchar_t*の CT2W
    wchar_t* → charの CW2A

    などがある。

    Unreal Engine 5 フォリッジ機能でメッシュに草を生やしてみる

    フォリッジ機能を使って草を生やすには、フォリッジモードに入る。

    フォリッジモード内で、「ここにフォリッジをドロップ」という位置にアクタをドロップする。例としてConeをドロップしてみると、「フォリッジタイプアセットの位置を選択」というダイアログが出てくる。これは生やす草などのオブジェクトを管理するディレクトリを指定するもので、わかりやすければどこでもいい。

    ペイントなどの要領でドラッグすればアクタを配置できる。

    なお、作業を終わるときは選択モードに移行する。

    Quixel Bridgeから草をダウンロードして配置

    Unreal Engine 5とQuixelをリンクしてモデルをインポートしてみる

    Quixel Bridgeの導入

    アドオンは予め入っているが、アカウントをリンクする必要がある。

    メールアドレスやパスワードを入力しなければならないが、今自分がEpic Gamesのアカウントを要求されているのか、Quixelのアカウントを要求されているのかを確認しながら進めないと間違えて時間がかかる。

    私の場合、以前作ったQuixelのアカウントがあったせいか、Quixel側の設定をしろと言われたので、GO THERE! をクリックしてQuixelのページを開く。

    Quixelのサイトへ行ったら、プラン選択のところでUNREAL ENGINEを選び、連携の設定を行う。

    これで、再度Unreal Engine側に戻ってSign Inすると使用できるようになる。

    読み込み

    Bridgeのウィンドウ内の一覧からドラッグ&ドロップすることで簡単にシーンに読み込める。

    Rustの手続き的マクロを考える(3)synで構文解析(2)

    synでの構文解析がどのようになっているかを調べるために、以下のようなコードを書く。

    parse_macro_inputで作成された構文木myinputをトレースするために、syn::visit::Visitを使用。ノードを再帰的に処理する。処理内容は「ノードを文字列化してコンパイル時に表示する」というもの。

    lib.rs

    extern crate proc_macro;
    
    use std::{string, str::FromStr};
    
    use proc_macro::TokenStream;
    
    use quote::ToTokens; // to_token_stream() を使うために必要
    
    use syn::{
        parse_macro_input,
        Expr,
    
        // Cargo.toml 内  syn = {"2.0", features = ["full","visit"] }
        visit   // "visit" が必要
    };
    
    
    use syn::visit::Visit; // vis.visit_expr() を使うために必要
    
    
    // 構造体を定義
    struct MyExprVisitor {
        indent: usize, // printでインデントしたいのでこのメンバを用意
    }
    

    // MyExprVisitor にvisit_expr()を実装
    // C++でいうと、「class MyExprVisitor : public syn::visit::Visit」に近い
    impl<'a> syn::visit::Visit<'a> for MyExprVisitor {
        fn visit_expr(&mut self, node: &'a Expr) {
    
            // インデント
            for _ in 0..self.indent {
                print!("  ");
            }
            // ノードを文字列化
            let astext = node.to_token_stream().to_string();
            println!("{}", astext);
            self.indent += 1;
            // 再帰的に処理
            syn::visit::visit_expr(self, node);
            self.indent -= 1;
        }
    }
    

    // 式のトークンストリームを処理するマクロ
    #[proc_macro]
    pub fn tokenstream_analyze_for_formula(input: TokenStream) -> TokenStream {
    
    
        // トークンストリームを解析
        let inputcopy = input.clone();
        let myinput:Expr = parse_macro_input!(inputcopy as Expr);
    
        println!("** 式の構文木ができているか確認 *********************");
        let mut myvis = MyExprVisitor{indent:0};
        myvis.visit_expr(&myinput);
    
    
        input
    }
    

    main.rs

    extern crate mymacro;
    
    
    fn main() {
    
        let value:i32;
        let seven:i32 = 7;
        
        
        // 式に対してマクロを適用
        mymacro::tokenstream_analyze_for_formula! {
    
            value = (seven + 5) * 2
    
        }
    
        print!("結果 {}",value);
    }
    

    コンパイル時出力

       Compiling mymain v0.1.0 (D:\mydev\Rust\mymacro-syn\mymain)
    ** 式の構文木ができているか確認 *********************
    value = (seven + 5) * 2
      value
      (seven + 5) * 2
        (seven + 5)
          seven + 5
            seven
            5
        2
        Finished dev [unoptimized + debuginfo] target(s) in 0.49s
    

    より詳しく解析する

    ただ文字列に変換しただけでは扱い方がよくわからないので、nodeをそれが何で(ここではExpr::Binary)、どのようなものが入っているのか(op,left,right)を取り出す。

    // MyExprVisitor にvisit_expr()を実装
    // C++でいうと、「class MyExprVisitor : public syn::visit::Visit」に近い
    impl<'a> syn::visit::Visit<'a> for MyExprVisitor {
        fn visit_expr(&mut self, node: &'a Expr) {
    
            let mut indentstr:String = "".to_string();
            // インデント
            for _ in 0..self.indent {
                indentstr.push_str(" ");
            };
    
    
            println!("{}***************",indentstr);
            match node {
                // Expr::Binaryはシンプルな加減乗除のような式
                // matchでnodeがExpr::Binaryであるかどうかを判定し、もしそうならその内容をmyitemへ代入
                Expr::Binary(myitem) => {
                    // if letでmyitemExprBinaryであるかどうかを判定し、もしそうならop,left,rightを取り出す
                    if let ExprBinary{op:myop, left:myleft, right:myright, ..} = myitem{
                        println!("{} @ {}",indentstr, myop.to_token_stream());
                        println!("{} @ {}",indentstr, myleft.to_token_stream());
                        println!("{} @ {}",indentstr, myright.to_token_stream());
                    }
                },
                _=>{}
            }
            println!("{}***************",indentstr);
    
            self.indent += 1;
            // 再帰的に処理
            syn::visit::visit_expr(self, node);
            self.indent -= 1;
    
        }
    }
    

    コンパイル時出力

       Compiling mymain v0.1.0 (D:\mydev\Rust\mymacro-syn\mymain)
    ** 式の構文木ができているか確認 *********************
    ***************
    ***************
     ***************
     ***************
     ***************
      @ *
      @ (seven + 5)
      @ 2
     ***************
      ***************
      ***************
       ***************
        @ +
        @ seven
        @ 5
       ***************
        ***************
        ***************
        ***************
        ***************
      ***************
      ***************
        Finished dev [unoptimized + debuginfo] target(s) in 0.32s