# 画面設計書 20-Custom Rendering

## 概要

本ドキュメントは、Dear ImGuiのサンプルアプリケーション「Custom Rendering」画面の設計仕様を定義する。本画面は、ImDrawList APIを使用したカスタム描画のサンプル実装である。

### 本画面の処理概要

本画面は、ImDrawListを使用して低レベルのカスタム描画を行う方法を実演する。プリミティブ図形、インタラクティブなキャンバス、バックグラウンド/フォアグラウンド描画、描画チャンネルの使用など、高度な描画テクニックを学ぶことができる。

**業務上の目的・背景**：ゲーム開発、グラフエディタ、ノードベースエディタなど、標準ウィジェットでは対応できないカスタムUI要素が必要になる場合がある。本画面は、ImDrawList APIを使用して任意の図形を描画する方法を示す。線、矩形、円、楕円、三角形、ベジェ曲線、グラデーションなど、さまざまなプリミティブを学ぶことができる。

**画面へのアクセス方法**：Demo Windowのメニューバーから「Examples」メニューを選択し、「Custom Rendering」を選択することで表示される。または、アプリケーションコード内で`ShowExampleAppCustomRendering(&show_app_custom_rendering)`を呼び出すことで直接表示可能。

**主要な操作・処理内容**：
1. Primitivesタブ：各種プリミティブ図形の描画デモ
2. Canvasタブ：マウスで線を描画するインタラクティブなキャンバス
3. BG/FG draw listsタブ：バックグラウンド/フォアグラウンド描画リストのデモ
4. Draw Channelsタブ：描画チャンネルによるZ順序制御のデモ

**画面遷移**：本画面はDemo Windowの「Examples」メニューから呼び出される。独立したウィンドウとして表示され、他の画面への直接的な遷移機能は持たない。

**権限による表示制御**：本画面は権限による表示制御を持たない。すべてのユーザーが同一の機能にアクセス可能である。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | Begin | 主機能 | ウィンドウの開始処理 |
| 25 | End | 主機能 | ウィンドウの終了処理 |
| 32 | GetWindowDrawList | 主機能 | ウィンドウ描画リストの取得 |
| 222 | GetBackgroundDrawList | 主機能 | 背景描画リストの取得 |
| 223 | GetForegroundDrawList | 主機能 | 前景描画リストの取得 |
| 67 | GetCursorScreenPos | 補助機能 | カーソル位置の取得 |
| 94 | InvisibleButton | 補助機能 | カスタム描画領域の作成 |

## 画面種別

デモ（カスタム描画サンプル）

## URL/ルーティング

N/A（ImGuiはURLベースのルーティングを持たない。`ShowExampleAppCustomRendering()`関数呼び出しによりウィンドウを表示）

## 入出力項目

| 項目名 | 型 | I/O | 必須 | 説明 |
|--------|-----|-----|------|------|
| p_open | bool* | I/O | No | ウィンドウの表示状態を制御するポインタ |

### Primitivesタブ

| 項目名 | 型 | I/O | 説明 |
|--------|-----|-----|------|
| sz | float (static) | I/O | 図形サイズ（デフォルト36） |
| thickness | float (static) | I/O | 線の太さ（デフォルト3） |
| ngon_sides | int (static) | I/O | N角形の辺数（デフォルト6） |
| circle_segments_override | bool/int (static) | I/O | 円のセグメント数オーバーライド |
| curve_segments_override | bool/int (static) | I/O | 曲線のセグメント数オーバーライド |
| colf | ImVec4 (static) | I/O | 図形の色 |

### Canvasタブ

| 項目名 | 型 | I/O | 説明 |
|--------|-----|-----|------|
| points | ImVector<ImVec2> (static) | I/O | 線の頂点リスト |
| scrolling | ImVec2 (static) | I/O | キャンバスのスクロール位置 |
| opt_enable_grid | bool (static) | I/O | グリッド表示の有効/無効 |
| opt_enable_context_menu | bool (static) | I/O | コンテキストメニューの有効/無効 |

## 表示項目

| 項目名 | 型 | 説明 |
|--------|-----|------|
| タブバー | TabBar | Primitives, Canvas, BG/FG draw lists, Draw Channels |
| グラデーション | RectFilledMultiColor | 白黒・緑赤のグラデーション |
| プリミティブ図形 | DrawList | N角形、円、楕円、矩形、三角形、線等 |
| キャンバス | InvisibleButton + DrawList | マウスで線を描画可能な領域 |
| 描画チャンネルデモ | DrawList | Z順序制御のデモ |

## イベント仕様

### 1-Primitivesタブの操作

各種パラメータを調整して、プリミティブ図形の描画をカスタマイズ：
- Size: 図形の基本サイズ（2-100）
- Thickness: 線の太さ（1-8）
- N-gon sides: 多角形の辺数（3-12）
- Circle/Curve segments override: セグメント数の手動設定
- Color: 図形の色（ColorEdit4）

### 2-Canvasタブでの線描画

- 左クリックドラッグ: 線を追加
- 右クリックドラッグ: キャンバスをパン
- 右クリック: コンテキストメニュー（Remove one/all）

### 3-BG/FG draw listsタブの操作

- Draw in Background draw list: 背景に円を描画
- Draw in Foreground draw list: 前景に円を描画

### 4-Draw Channelsタブの確認

描画順序と描画チャンネルの効果を視覚的に確認：
- 通常: 青→赤の順で描画され、赤が前面
- チャンネル使用: 青をチャンネル1、赤をチャンネル0に描画すると、描画順序が逆転

## データベース更新仕様

本画面はデータベースを使用しない。

### 操作別データベース影響一覧

N/A（データベースアクセスなし）

## メッセージ仕様

| 表示テキスト | 表示場所 | 説明 |
|-------------|---------|------|
| "Gradients" | Primitivesタブ | グラデーションセクションの見出し |
| "All primitives" | Primitivesタブ | プリミティブセクションの見出し |
| "Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu." | Canvasタブ | 操作説明 |

## 例外処理

| 状態 | 処理内容 |
|------|----------|
| ウィンドウ非表示時 | Begin()がfalseを返した場合、End()を呼び出して即座にリターン |
| キャンバスサイズが小さい | 最小50x50に制限 |

## 備考

- GetWindowDrawList()でウィンドウの描画リストを取得
- GetBackgroundDrawList()は全ウィンドウの背後に描画
- GetForegroundDrawList()は全ウィンドウの前面に描画
- ChannelsSplit/ChannelsSetCurrent/ChannelsMergeで描画順序を制御
- InvisibleButton()でカスタム描画領域のインタラクションを実装
- PushClipRect/PopClipRectでクリッピング領域を設定

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

ImDrawListの基本構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui.h | `imgui.h` | ImDrawList構造体とメソッドの宣言を確認 |
| 1-2 | imgui_demo.cpp | `imgui_demo.cpp` | 9907-9912行のPathConcaveShape()ヘルパー関数 |

**読解のコツ**: ImDrawListは描画コマンドをバッファリングし、後でレンダリングバックエンドに渡す。頂点とインデックスを追加するAdd〜系メソッドと、パスベースの描画を行うPath〜系メソッドがある。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui_demo.cpp | `imgui_demo.cpp` | ShowExampleAppCustomRendering()関数（9915行〜）全体を確認 |

**主要処理フロー**:
1. **9917-9921行**: Begin()でウィンドウを開始、失敗時は早期リターン
2. **9929行**: BeginTabBar()でタブバーを開始
3. **9931-10056行**: Primitivesタブの処理
4. **10058-10153行**: Canvasタブの処理
5. **10155-10171行**: BG/FG draw listsタブの処理
6. **10173-10200行**: Draw Channelsタブの処理

#### Step 3: Primitivesタブを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui_demo.cpp | `imgui_demo.cpp` | 9931-10056行のPrimitivesタブ描画処理 |

**主要処理フロー**:
- **9934行**: GetWindowDrawList()で描画リスト取得
- **9939-9956行**: グラデーション矩形の描画
- **9959-10023行**: ストローク図形の描画（2行ループ）
- **10026-10053行**: 塗りつぶし図形の描画

#### Step 4: Canvasタブを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | imgui_demo.cpp | `imgui_demo.cpp` | 10058-10153行のCanvasタブ描画処理 |

**主要処理フロー**:
- **10082-10086行**: キャンバスサイズの計算
- **10095行**: InvisibleButton()でインタラクション領域を作成
- **10102-10113行**: マウスドラッグによる線の追加
- **10138-10150行**: グリッドと線の描画

### プログラム呼び出し階層図

```
ShowExampleAppCustomRendering(bool* p_open)
    |
    +-- ImGui::Begin("Example: Custom rendering", p_open)
    |
    +-- ImGui::BeginTabBar("##TabBar")
            |
            +-- [Primitives Tab]
            |   +-- GetWindowDrawList()
            |   +-- AddRectFilledMultiColor() // グラデーション
            |   +-- for (2回ループ) // ストローク/塗りつぶし
            |           +-- AddNgon(), AddCircle(), AddEllipse()
            |           +-- AddRect(), AddTriangle()
            |           +-- PathArcTo(), PathStroke()/PathFillConvex()
            |           +-- AddBezierQuadratic(), AddBezierCubic()
            |
            +-- [Canvas Tab]
            |   +-- InvisibleButton("canvas")
            |   +-- IsItemHovered(), IsItemActive()
            |   +-- IsMouseClicked(), IsMouseDown(), IsMouseDragging()
            |   +-- BeginPopup("context")
            |   +-- PushClipRect() / PopClipRect()
            |   +-- AddLine() // グリッド、ユーザー線
            |
            +-- [BG/FG draw lists Tab]
            |   +-- GetBackgroundDrawList()->AddCircle()
            |   +-- GetForegroundDrawList()->AddCircle()
            |
            +-- [Draw Channels Tab]
                +-- draw_list->ChannelsSplit(2)
                +-- draw_list->ChannelsSetCurrent(1) // 青
                +-- draw_list->ChannelsSetCurrent(0) // 赤
                +-- draw_list->ChannelsMerge()
```

### データフロー図

```
[入力]                    [処理]                         [出力]

パラメータ変更 ---------> プリミティブ描画
                          |
                          +-> ImDrawList->Add〜() ------> GPU頂点バッファ

マウス操作 -------------> InvisibleButton判定
                          |
                          +-> points配列更新 -----------> 線の追加

BG/FGチェック ---------> GetBackground/ForegroundDrawList()
                          |
                          +-> AddCircle() --------------> 全体の前景/背景に描画

チャンネル設定 ---------> ChannelsSplit/SetCurrent
                          |
                          +-> ChannelsMerge() ----------> Z順序制御された描画
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui_demo.cpp | `imgui_demo.cpp` | ソース | ShowExampleAppCustomRendering()関数のデモ実装 |
| imgui.h | `imgui.h` | ヘッダー | ImDrawList, ImDrawCmd, ImDrawVert等の宣言 |
| imgui.cpp | `imgui.cpp` | ソース | GetWindowDrawList, GetBackground/ForegroundDrawListの実装 |
| imgui_draw.cpp | `imgui_draw.cpp` | ソース | ImDrawListのAdd〜, Path〜メソッドの実装 |
