# 画面設計書 43-OpenGL Lease

## 概要

本ドキュメントは、Avalonia UIフレームワークのControlCatalogサンプルアプリケーションにおける「OpenGL Lease」デモページの画面設計書です。

### 本画面の処理概要

OpenGL Leaseページは、AvaloniaフレームワークのCompositionレンダリングシステムと統合したOpenGL描画の高度な実装例をデモンストレーションする画面です。CompositionCustomVisualHandlerを使用して、Skia/OpenGLコンテキストのリース機構を通じた3Dレンダリングを実現しています。

**業務上の目的・背景**：OpenGlControlBaseを使用する標準的な方法とは異なり、より細かい制御が必要な場合のOpenGL統合手法を示しています。Skiaレンダリングパイプラインとの統合、フレームバッファオブジェクト（FBO）の手動管理、コンテキストのリース/リリースの正しいパターンを学ぶための参考実装として提供されています。GPUインターオペレーションが必要な高度なグラフィックスアプリケーションでの使用を想定しています。

**画面へのアクセス方法**：MainWindowからMainViewのHamburgerMenuを開き、「OpenGL Lease」メニュー項目を選択することでアクセスできます。

**主要な操作・処理内容**：
1. CompositionCustomVisualによる3Dティーポットモデルのレンダリング
2. Yaw（ヨー）スライダーによるY軸回転制御
3. Pitch（ピッチ）スライダーによるX軸回転制御
4. Roll（ロール）スライダーによるZ軸回転制御
5. Discoスライダーによるアニメーション効果の適用
6. SkiaSharp APIリースを通じたOpenGL描画の統合

**画面遷移**：本画面は単独のデモページであり、MainViewのHamburgerMenuから遷移します。他画面への直接遷移機能は持ちません。

**権限による表示制御**：本デモ画面では権限による表示制御は実装されていません。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 106 | OpenGL | 主機能 | OpenGLコンテキスト管理とレンダリング |

## 画面種別

デモ / 3Dレンダリング（Composition統合）

## URL/ルーティング

ControlCatalog内のHamburgerMenuナビゲーションによるページ切り替え（URL/ルーティング定義なし）

## 入出力項目

| 項目名 | 項目種別 | データ型 | 必須 | 説明 |
|--------|----------|----------|------|------|
| Yaw | 入力 | float | - | Y軸回転角度（0-10） |
| Pitch | 入力 | float | - | X軸回転角度（0-10） |
| Roll | 入力 | float | - | Z軸回転角度（0-10） |
| Disco | 入力 | float | - | ディスコエフェクト強度（0-1） |

## 表示項目

| 項目名 | 表示位置 | 説明 |
|--------|----------|------|
| Viewportコントロール | 画面全体 | CompositionCustomVisualによる3Dレンダリング表示 |
| Yawスライダー | 右パネル | Y軸回転制御 |
| Pitchスライダー | 右パネル | X軸回転制御 |
| Rollスライダー | 右パネル | Z軸回転制御 |
| Discoスライダー | 右パネル | アニメーション効果制御 |

## イベント仕様

### 1-ViewportAttachedToVisualTree

ViewportコントロールがVisualTreeにアタッチされた際に呼び出される。ElementCompositionからCompositorを取得し、CompositionCustomVisual（GlVisual）を作成してViewportの子ビジュアルとして設定する。

### 2-ViewportDetachedFromVisualTree

ViewportコントロールがVisualTreeからデタッチされた際に呼び出される。DisposeMessageを送信してOpenGLリソースを解放し、子ビジュアルをnullに設定してクリーンアップする。

### 3-KnobsPropertyChanged

GlPageKnobsのYaw/Pitch/Roll/Discoプロパティが変更されると呼び出される。GetParametersで現在のパラメータを取得し、SendHandlerMessageでGlVisualにパラメータを送信する。

### 4-GlVisual.OnRender

CompositionCustomVisualHandlerのOnRenderオーバーライド。ISkiaSharpApiLeaseFeatureを取得し、プラットフォームグラフィックスAPIをリースしてOpenGLレンダリングを実行する。結果をSkiaCanvasに描画する。

### 5-GlVisual.OnAnimationFrameUpdate

アニメーションフレーム更新時に呼び出される。Disco値が閾値を超えている場合、または再描画が必要な場合にInvalidateを呼び出して再描画をトリガーする。

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

本画面はUIコントロールのデモ画面であり、データベースへのアクセス・更新は行いません。

## メッセージ仕様

本画面では特定のメッセージ表示は実装されていません。

## 例外処理

- OpenGLコンテキストが利用できない場合は描画をスキップ
- SkiaのGrContextがnullの場合は早期リターン
- コンテキスト切り替え時は既存のFBOとコンテンツを破棄し再初期化
- Deinitエラー時はコンソールにエラー内容を出力

## 備考

- OpenGlControlBaseではなくCompositionCustomVisualHandlerを使用
- ISkiaSharpApiLeaseFeatureを通じてSkiaとOpenGLの統合を実現
- OpenGlFboクラスでフレームバッファオブジェクトを管理
- コンテキストの変更を検知して適切にリソースを再初期化
- パラメータはSendHandlerMessageを通じてスレッドセーフに送信

---

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

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

### 推奨読解順序

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

パラメータクラスとメッセージングパターンを理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | OpenGlLeasePage.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml.cs` | Parametersクラス（145-151行）でYaw/Pitch/Roll/Discoの定義を確認 |
| 1-2 | OpenGlLeasePage.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml.cs` | DisposeMessageクラス（153-156行）でリソース解放メッセージを確認 |

**読解のコツ**: CompositionCustomVisualHandlerのメッセージングパターン（SendHandlerMessage/OnMessage）を理解しておくと良い。

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

VisualTree接続時の初期化処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | OpenGlLeasePage.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml.cs` | ViewportAttachedToVisualTree（177-185行）でCompositionCustomVisual作成 |
| 2-2 | OpenGlLeasePage.xaml | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml` | Viewportコントロール定義（7行）でイベントハンドラ接続 |

**主要処理フロー**:
1. **179行**: ElementCompositionからビジュアル取得
2. **182行**: CreateCustomVisualでGlVisualインスタンス作成
3. **183行**: SetElementChildVisualで子ビジュアル設定
4. **184行**: UpdateSizeで初期サイズ設定

#### Step 3: GlVisualクラスを理解する

CompositionCustomVisualHandlerの実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | OpenGlLeasePage.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml.cs` | GlVisualクラス定義（19-143行）全体構造 |
| 3-2 | OpenGlLeasePage.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml.cs` | OnRender（34-93行）でSkia/OpenGL統合レンダリング |

**主要処理フロー**:
- **36-37行**: Disco値が閾値以上なら次アニメーションフレームを登録
- **43-46行**: ISkiaSharpApiLeaseFeatureからSkiaリースを取得
- **50-53行**: プラットフォームグラフィックスAPIをリースしてIGlContext取得
- **66-68行**: OpenGlFboの初期化・リサイズ
- **81-82行**: OpenGLレンダリング実行
- **84-91行**: スナップショットをSkiaCanvasに描画

#### Step 4: リソース管理を理解する

コンテキスト変更時の再初期化とリソース解放を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | OpenGlLeasePage.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml.cs` | OnMessage（106-142行）でパラメータ更新とリソース解放 |
| 4-2 | OpenGlLeasePage.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml.cs` | ViewportDetachedFromVisualTree（200-206行）でクリーンアップ |

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

```
OpenGlLeasePage (UserControl)
    │
    ├─ Viewport (Control)
    │      ├─ AttachedToVisualTree
    │      │      └─ ViewportAttachedToVisualTree()
    │      │             ├─ CreateCustomVisual(GlVisual)
    │      │             └─ SetElementChildVisual()
    │      │
    │      └─ DetachedFromVisualTree
    │             └─ ViewportDetachedFromVisualTree()
    │                    └─ SendHandlerMessage(DisposeMessage)
    │
    ├─ GlVisual (CompositionCustomVisualHandler)
    │      ├─ OnRender()
    │      │      ├─ ISkiaSharpApiLeaseFeature.Lease()
    │      │      ├─ TryLeasePlatformGraphicsApi()
    │      │      ├─ OpenGlFbo管理
    │      │      ├─ OpenGlContent.OnOpenGlRender()
    │      │      └─ SkCanvas.DrawImage()
    │      │
    │      ├─ OnAnimationFrameUpdate()
    │      │      └─ Invalidate()
    │      │
    │      └─ OnMessage()
    │             ├─ Parameters処理 → RegisterForNextAnimationFrameUpdate()
    │             └─ DisposeMessage処理 → リソース解放
    │
    └─ GlPageKnobs (UserControl)
           └─ PropertyChanged → KnobsPropertyChanged()
                  └─ SendHandlerMessage(Parameters)
```

### データフロー図

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

スライダー操作 ──────────▶ GlPageKnobs ─────────────▶ Parametersメッセージ
(Yaw/Pitch/Roll/Disco)    └─ KnobsPropertyChanged()      │
                                                         ▼
                          GlVisual.OnMessage() ◀────────┘
                               │
                               ▼
                          RegisterForNextAnimationFrameUpdate()
                               │
                               ▼
                          OnRender()
                               ├─ SkiaSharp APIリース
                               ├─ OpenGL コンテキストリース
                               ├─ FBO描画
                               ├─ OpenGlContent.OnOpenGlRender()
                               └─ Snapshot → SkCanvas
                                    │
                                    ▼
                               画面表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| OpenGlLeasePage.xaml | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml` | XAML | 画面レイアウト定義 |
| OpenGlLeasePage.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlLeasePage.xaml.cs` | ソース | コードビハインド・GlVisualハンドラ |
| OpenGlContent.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlContent.cs` | ソース | OpenGLレンダリングロジック |
| OpenGlFbo.cs | `samples/ControlCatalog/Pages/OpenGl/OpenGlFbo.cs` | ソース | フレームバッファオブジェクト管理 |
| GlPageKnobs.xaml | `samples/ControlCatalog/Pages/OpenGl/GlPageKnobs.xaml` | XAML | 操作パネルレイアウト |
| GlPageKnobs.xaml.cs | `samples/ControlCatalog/Pages/OpenGl/GlPageKnobs.xaml.cs` | ソース | 操作パネルプロパティ定義 |
