12#include <imgui_impl_dx12.h>
13#include <imgui_impl_win32.h>
37 void Line(std::string_view text) {
38 ImGui::TextUnformatted(text.data(), text.data() + text.size());
42 return speed >= 1.0 ? std::format(
"×{:g}", speed) : std::format(
"×1/{:g}", 1.0 / speed);
61 Window& window, ID3D12Device* device,
gpu::Queue& direct, DXGI_FORMAT format, uint32_t frameCount) {
63 std::unique_ptr<EditorOverlay> overlay(
new EditorOverlay(window, frameCount));
64 overlay->m_lab = std::make_unique<LabPanel>(device);
65 if (!overlay->CreateGpuObjects(device, frameCount))
66 return std::unexpected(
"エディタの描画のリソースを作れない");
69 ImGui::CreateContext();
70 overlay->m_contextCreated =
true;
72 ImGuiIO& io = ImGui::GetIO();
73 io.IniFilename =
nullptr;
74 ImGui::StyleColorsDark();
75 overlay->LoadJapaneseFont();
77 if (!overlay->InitializeBackends(device, direct, format))
78 return std::unexpected(
"ImGui の Win32 / DX12 の backend を作れない");
80 window.
SetMessageHook([](HWND handle, UINT message, WPARAM wParam, LPARAM lParam) {
93 ImGui_ImplDX12_Shutdown();
96 ImGui_ImplWin32_Shutdown();
99 ImGui::DestroyContext();
103 const D3D12_DESCRIPTOR_HEAP_DESC heapDesc{.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
104 .NumDescriptors = SRV_DESCRIPTOR_COUNT,
105 .Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE};
106 if (FAILED(device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&
m_srvHeap))))
109 m_srvIncrement = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
110 for (uint32_t slot = SRV_DESCRIPTOR_COUNT; slot > 0; --slot)
114 if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&
frame.allocator))))
118 if (frameCount == 0 ||
119 FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
m_frames.front().allocator.Get(),
120 nullptr, IID_PPV_ARGS(&
m_list)))) {
124 return SUCCEEDED(
m_list->Close());
132 ImGui_ImplDX12_InitInfo info;
133 info.Device = device;
134 info.CommandQueue = direct.
Native();
135 info.NumFramesInFlight =
static_cast<int>(
m_frames.size());
136 info.RTVFormat = format;
137 info.DSVFormat = DXGI_FORMAT_UNKNOWN;
138 info.UserData =
this;
139 info.SrvDescriptorHeap =
m_srvHeap.Get();
149 std::array<wchar_t, MAX_PATH> windows{};
150 const UINT length = GetWindowsDirectoryW(windows.data(),
static_cast<UINT
>(windows.size()));
151 const fs::path fonts = fs::path(std::wstring_view(windows.data(), length)) / L
"Fonts";
153 for (
const std::wstring_view file : JAPANESE_FONT_FILES) {
154 const fs::path path = fonts / file;
155 std::error_code error;
156 if (!fs::exists(path, error))
159 const std::string utf8 =
ToUtf8(path.wstring());
160 if (ImGui::GetIO().Fonts->AddFontFromFileTTF(utf8.c_str(), FONT_SIZE_PIXELS) !=
nullptr)
170 D3D12_GPU_DESCRIPTOR_HANDLE* gpuHandle) {
172 IM_ASSERT(!overlay->m_freeSrvSlots.empty());
174 const uint32_t slot = overlay->m_freeSrvSlots.back();
175 overlay->m_freeSrvSlots.pop_back();
177 *cpuHandle = overlay->m_srvHeap->GetCPUDescriptorHandleForHeapStart();
178 cpuHandle->ptr +=
size_t{slot} * overlay->m_srvIncrement;
179 *gpuHandle = overlay->m_srvHeap->GetGPUDescriptorHandleForHeapStart();
180 gpuHandle->ptr += uint64_t{slot} * overlay->m_srvIncrement;
184 D3D12_GPU_DESCRIPTOR_HANDLE ) {
186 const size_t start = overlay->m_srvHeap->GetCPUDescriptorHandleForHeapStart().ptr;
187 overlay->m_freeSrvSlots.push_back(
static_cast<uint32_t
>((cpuHandle.ptr - start) / overlay->m_srvIncrement));
193 return ImGui::GetIO().WantCaptureMouse;
197 return ImGui::GetIO().WantCaptureKeyboard;
206 request.
togglePause = ImGui::IsKeyPressed(ImGuiKey_Space,
false);
207 if (time.
Paused() && ImGui::IsKeyPressed(ImGuiKey_N,
true))
216 ImGui_ImplDX12_NewFrame();
217 ImGui_ImplWin32_NewFrame();
228 return Merge(keys, buttons);
233 ImGui::SetNextWindowPos({PANEL_MARGIN_PIXELS, PANEL_MARGIN_PIXELS}, ImGuiCond_FirstUseEver);
234 ImGui::Begin(
"時間",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
237 if (ImGui::Button(time.
Paused() ?
"動かす (Space)" :
"止める (Space)"))
241 ImGui::BeginDisabled(!time.
Paused());
242 if (ImGui::Button(
"1 刻み (N)"))
246 if (ImGui::Button(
"60 刻み"))
249 ImGui::EndDisabled();
252 if (ImGui::ArrowButton(
"##slower", ImGuiDir_Left))
256 Line(std::format(
"速さ {}", FormatSpeed(time.
Speed())));
258 if (ImGui::ArrowButton(
"##faster", ImGuiDir_Right))
262 if (ImGui::Button(
"等速"))
268 Line(std::format(
"動いている: 刻み {}", status.
tick));
269 else if (status.
unit == 0)
270 Line(std::format(
"止まっている: 刻み {} の前", status.
tick));
272 Line(std::format(
"止めている: 刻み {} の残りを進めている", status.
tick));
274 Line(std::format(
"1 刻みずつ進めた: {} 刻み", time.
SteppedTicks()));
283 ImGui::SeparatorText(
"巻き戻す(保存点 + 再生)");
290 ImGui::TextDisabled(
"保存点はまだ無い(%llu 刻みごとに写す)",
295 uint64_t rewindTick = UINT64_MAX;
298 [&](uint64_t tick) { return tick < status.tick; });
300 if (ImGui::Button(
"1 つ前の保存点へ") && previous != status.
savePointTicks.rend())
301 rewindTick = *previous;
303 ImGui::EndDisabled();
306 if (ImGui::SmallButton(std::format(
"{}##save", tick).c_str()))
315 ImGui::SeparatorText(
"反応表");
316 Line(std::format(
"版 {:016x} 差し替え {} 回 読めなかった {} 回", table.
version, table.
swaps, table.
failures));
318 ImGui::TextDisabled(
"ファイルを見ていない(再生中か、--editor でない)");
320 Line(
"読めた表が刻みの境界を待っている(止めているなら 1 刻み進める)");
322 ImGui::TextDisabled(
"パッケージのファイルを見ている(保存すると読み直す)");
327 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 40.0f);
329 ImGui::TextColored(ImVec4(1.0f, 0.45f, 0.4f, 1.0f),
"今の表のまま: %s", table.
message.c_str());
331 ImGui::TextWrapped(
"%s", table.
message.c_str());
333 ImGui::PopTextWrapPos();
337 ImGui::SetNextWindowPos({PANEL_MARGIN_PIXELS, 240.0f}, ImGuiCond_FirstUseEver);
338 ImGui::Begin(
"状態",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
341 Line(std::format(
"刻み {}(単位 {} / {}) 未処理 {:.1f} 刻み 捨てた刻み {}", status.
tick, status.
unit,
344 Line(std::format(
"エネルギー {} mJ 計算したブロック {}",
static_cast<int64_t
>(status.
energyMillijoules),
357 Line(std::format(
"表示: {}", status.
view));
359 Line(
"再生中(窓の操作は世界に入らない)");
367 if (ImGui::CollapsingHeader(
"操作")) {
368 Line(
"左クリック: つつく(断面) Shift + 左: 押す");
369 Line(
"右ドラッグ: 回る 中ドラッグ: 平行移動 ホイール: 寄る");
370 Line(
"1/2/3: 表示 X/Y/Z・Q/E: 断面 L: 対数 B: 活性 O: 透視 R: 戻す");
371 Line(
"T: トレース P: 覗き窓 Space: 止める N: 1 刻み");
380 D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView) {
385 if (FAILED(
frame.allocator->Reset()) || FAILED(
m_list->Reset(
frame.allocator.Get(),
nullptr)))
388 const D3D12_RESOURCE_BARRIER toRenderTarget =
gpu::Transition(backBuffer, D3D12_RESOURCE_STATE_PRESENT,
389 D3D12_RESOURCE_STATE_RENDER_TARGET);
390 m_list->ResourceBarrier(1, &toRenderTarget);
391 m_list->OMSetRenderTargets(1, &renderTargetView, FALSE,
nullptr);
393 ID3D12DescriptorHeap* heaps[] = {
m_srvHeap.Get()};
394 m_list->SetDescriptorHeaps(1, heaps);
395 ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(),
m_list.Get());
397 const D3D12_RESOURCE_BARRIER toPresent =
gpu::Transition(backBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET,
398 D3D12_RESOURCE_STATE_PRESENT);
399 m_list->ResourceBarrier(1, &toPresent);
400 if (FAILED(
m_list->Close()))
void SetMessageHook(MessageHook hook)
static void AllocateDescriptor(::ImGui_ImplDX12_InitInfo *info, D3D12_CPU_DESCRIPTOR_HANDLE *cpuHandle, D3D12_GPU_DESCRIPTOR_HANDLE *gpuHandle)
bool CreateGpuObjects(ID3D12Device *device, uint32_t frameCount)
EditorOverlay(const EditorOverlay &)=delete
std::unique_ptr< LabPanel > m_lab
void BuildStatusPanel(const EditorStatus &status) const
TimeRequest TakeShortcuts(const TimeControl &time) const
ComPtr< ID3D12DescriptorHeap > m_srvHeap
bool Submit(gpu::Queue &direct, ID3D12Resource *backBuffer, D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView)
uint64_t BuildRewind(const EditorStatus &status) const
bool WantsKeyboard() const
void BuildReactionTable(const ReactionTableStatus &table) const
TimeRequest BuildTimePanel(const EditorStatus &status, const TimeControl &time) const
static std::expected< std::unique_ptr< EditorOverlay >, std::string > Create(Window &window, ID3D12Device *device, gpu::Queue &direct, DXGI_FORMAT format, uint32_t frameCount)
static void FreeDescriptor(::ImGui_ImplDX12_InitInfo *info, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle)
ComPtr< ID3D12GraphicsCommandList > m_list
std::vector< uint32_t > m_freeSrvSlots
bool WantsPointer() const
bool InitializeBackends(ID3D12Device *device, gpu::Queue &direct, DXGI_FORMAT format)
TimeRequest Build(const EditorStatus &status, const TimeControl &time)
std::vector< FrameSlot > m_frames
uint64_t SteppedTicks() const
bool WaitCpu(uint64_t value) const
bool IsComplete(uint64_t value) const
ID3D12CommandQueue * Native() const
uint64_t Submit(std::span< ID3D12CommandList *const > lists)
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
TimeRequest Merge(const TimeRequest &a, const TimeRequest &b)
std::string FormatSpeed(double speed)
constexpr float FONT_SIZE_PIXELS
constexpr std::array< std::wstring_view, 3 > JAPANESE_FONT_FILES
void Line(std::string_view text)
constexpr float PANEL_MARGIN_PIXELS
constexpr uint32_t SRV_DESCRIPTOR_COUNT
void BuildGraphPanel(const GraphPanelStatus &status)
D3D12_RESOURCE_BARRIER Transition(ID3D12Resource *resource, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after)
void Log(Channel channel, Level level, FormatWithLocation< std::type_identity_t< Args >... > pattern, Args &&... args)
std::string ToUtf8(std::wstring_view text)
std::vector< uint64_t > savePointTicks
ReactionTableStatus reactionTable
uint64_t energyMillijoules
double budgetMilliseconds
double renderGpuMilliseconds
std::string rewindUnavailable
uint64_t saveIntervalTicks
double simGpuMilliseconds