Chapter 05

DockSpace

ousttrue
ousttrue
2022.01.13に更新

imgui docking branch の機能。

dockspace 有効にした状態で ImGui.Begin して作った Window は dock になる。

初期化

dockspace は docknode のツリーとして表現されます。
root の window を作成してビューポート全体を覆うようにします。

        void DockSpace(string name)
        {
            var flags = (ImGuiWindowFlags.MenuBar
                     | ImGuiWindowFlags.NoDocking
                     | ImGuiWindowFlags.NoBackground
                     | ImGuiWindowFlags.NoTitleBar
                     | ImGuiWindowFlags.NoCollapse
                     | ImGuiWindowFlags.NoResize
                     | ImGuiWindowFlags.NoMove
                     | ImGuiWindowFlags.NoBringToFrontOnFocus
                     | ImGuiWindowFlags.NoNavFocus
                     );

            var viewport = ImGui.GetMainViewport();
            var pos = viewport.Pos;
            var size = viewport.Size;
            ImGui.SetNextWindowPos(pos);
            ImGui.SetNextWindowSize(size);
            ImGui.SetNextWindowViewport(viewport.ID);
            ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0.0f);
            ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0.0f);
            ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.zero);

            // DockSpace
            ImGui.Begin(name, flags);
            ImGui.PopStyleVar(3);
            var dockspace_id = ImGui.GetID(name);
            ImGui.DockSpace(dockspace_id, Vector2.zero, ImGuiDockNodeFlags.PassthruCentralNode);
            ImGui.End();
        }

よく使うパターン

Dock の表示・非表示と Menu を連動させます。

    public delegate void DrawDelegate(ref bool p_open);

    public class Dock
    {
        public readonly string MenuLabel;
        public readonly string MenuShortCut;
        public readonly DrawDelegate Show;
        public bool IsOpen = true;

        public Dock(string name, string shortCut, DrawDelegate show)
        {
            MenuLabel = name;
            MenuShortCut = shortCut;
            Show = show;
        }

        public void Draw()
        {
            if (IsOpen)
            {
                Show(ref IsOpen);
            }
        }
    }
// MainMenuBar でビューポートにメニューバーを作る
            if (ImGui.BeginMainMenuBar())
            {
                if (ImGui.BeginMenu("Window"))
                {
                    foreach (var dock in Docks)
                    {
		        // Dockの表示状態と chekmark を連動
                        ImGui.MenuItem(dock.MenuLabel, dock.MenuShortCut, ref dock.IsOpen);
                    }
                    ImGui.EndMenu();
                }
                ImGui.EndMainMenuBar();
            }
	    
            foreach (var dock in Docks)
            {
	        // dock の描画
                dock.Draw();
            }	    

初期化時に dock をリストに投入します。

            _dockspace.Docks.Add(new Dock("demo", "", (ref bool p_open) => { ImGui.ShowDemoWindow(ref p_open); }));
            _dockspace.Docks.Add(new Dock("metrics", "", (ref bool p_open) => { ImGui.ShowMetricsWindow(ref p_open); }));

            _dockspace.Docks.Add(new Dock("hello", "", (ref bool p_open) =>
            {
                if (p_open)
                {
                    if (ImGui.Begin("hello", ref p_open))
                    {
                        ImGui.TextUnformatted($"sample{_count}");
                    }
                    ImGui.End();
                }
            }));

RenderTarget をビューに表示する

        Vector4 _color = new Vector4(0, 0, 0, 1);
        [SerializeField]
        public RenderTexture _viewport;
        IntPtr RenderView(int w, int h)
        {
            if (_viewport != null && (_viewport.width!=w || _viewport.height!=h))
            {
                RenderTexture.Destroy(_viewport);
                _viewport = null;
            }
            if (_viewport == null)
            {
                _viewport = new RenderTexture(w, h, 24, RenderTextureFormat.ARGB32);
            }

            RenderTexture rt = RenderTexture.active;
            RenderTexture.active = _viewport;
            GL.Clear(true, true, _color);
            RenderTexture.active = rt;

// UImGuiUtility.GetTextureId で得た IntPtr を ImGui.Image などに渡す
            return UImGui.UImGuiUtility.GetTextureId(_viewport);
        }
	
            _dockspace.Docks.Add(new Dock("view", "", (ref bool p_open) =>
            {
                if (p_open)
                {
                    ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.zero);
                    if (ImGui.Begin("view", ref p_open, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
                    {
                        var size = ImGui.GetContentRegionAvail();
			
			// ImGui の Window サイズで描画して texture 参照を得る
                        var ptr = RenderView((int)size.x, (int)size.y);
                        if (ptr != IntPtr.Zero)
                        {
                            ImGui.BeginChild("image");
                            ImGui.Image(ptr, size, new Vector2(0, 1), new Vector2(1, 0));
                            ImGui.EndChild();
                        }
                    }
                    ImGui.End();
                }
            }));	

MouseEvent のハンドリング

ImGui の イベントを Viewport(mouse) に送る。

            var io = ImGui.GetIO();
            if (_viewHover && io.MouseWheel != 0)
            {
                _turnTable.Dolly(io.MouseWheel);
            }
            if (ImGui.IsMouseDragging(ImGuiMouseButton.Left) || ImGui.IsMouseDragging(ImGuiMouseButton.Right) || ImGui.IsMouseDragging(ImGuiMouseButton.Middle))
            {
                _turnTable.Move(io.DisplaySize, (int)io.MouseDelta.x, (int)-io.MouseDelta.y, io.MouseDown[0], io.MouseDown[1], io.MouseDown[2]);
            }

            var (pos, rot) = _turnTable.Calc();
            ViewCamera.transform.SetPositionAndRotation(pos, rot);