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);