/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2015 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include #include #include "third_party/elemental-forms/src/el/util/debug.h" #include "third_party/imgui/imgui.h" #include "xenia/base/clock.h" #include "xenia/base/logging.h" #include "xenia/base/main.h" #include "xenia/base/platform_win.h" #include "xenia/base/threading.h" #include "xenia/profiling.h" #include "xenia/ui/imgui_drawer.h" #include "xenia/ui/window.h" namespace xe { namespace ui { // Implemented in one of the window_*_demo.cc files under a subdir. std::unique_ptr CreateDemoContext(Window* window); std::unique_ptr imgui_drawer_; int window_demo_main(const std::vector& args) { Profiler::Initialize(); Profiler::ThreadEnter("main"); // Create run loop and the window. auto loop = ui::Loop::Create(); auto window = xe::ui::Window::Create(loop.get(), GetEntryInfo().name); loop->PostSynchronous([&window]() { xe::threading::set_name("Win32 Loop"); xe::Profiler::ThreadEnter("Win32 Loop"); if (!window->Initialize()) { FatalError("Failed to initialize main window"); return; } }); window->on_closed.AddListener([&loop](xe::ui::UIEvent* e) { loop->Quit(); XELOGI("User-initiated death!"); imgui_drawer_.reset(); exit(1); }); loop->on_quit.AddListener([&window](xe::ui::UIEvent* e) { window.reset(); }); // Main menu. auto main_menu = MenuItem::Create(MenuItem::Type::kNormal); auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&File"); { file_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, L"&Close", L"Alt+F4", [&window]() { window->Close(); })); } main_menu->AddChild(std::move(file_menu)); auto debug_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&Debug"); { debug_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, L"Toggle Profiler &Display", L"F3", []() { Profiler::ToggleDisplay(); })); debug_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, L"&Pause/Resume Profiler", L"`", []() { Profiler::TogglePause(); })); } main_menu->AddChild(std::move(debug_menu)); window->set_main_menu(std::move(main_menu)); // Initial size setting, done here so that it knows the menu exists. window->Resize(1920, 1200); // Create the graphics context used for drawing and setup the window. loop->PostSynchronous([&window]() { // Create context and give it to the window. // The window will finish initialization wtih the context (loading // resources, etc). auto context = CreateDemoContext(window.get()); window->set_context(std::move(context)); // Setup the profiler display. GraphicsContextLock context_lock(window->context()); Profiler::set_window(window.get()); // Initialize the ImGui renderer we'll use. imgui_drawer_ = std::make_unique(window.get()); // Show the elemental-forms debug UI so we can see it working. el::util::ShowDebugInfoSettingsForm(window->root_element()); }); window->on_key_char.AddListener([](xe::ui::KeyEvent* e) { auto& io = ImGui::GetIO(); if (e->key_code() > 0 && e->key_code() < 0x10000) { io.AddInputCharacter(e->key_code()); } e->set_handled(true); }); window->on_key_down.AddListener([](xe::ui::KeyEvent* e) { auto& io = ImGui::GetIO(); io.KeysDown[e->key_code()] = true; switch (e->key_code()) { case 0x72: { // F3 Profiler::ToggleDisplay(); } break; case 16: { io.KeyShift = true; } break; case 17: { io.KeyCtrl = true; } break; } }); window->on_key_up.AddListener([](xe::ui::KeyEvent* e) { auto& io = ImGui::GetIO(); io.KeysDown[e->key_code()] = false; switch (e->key_code()) { case 16: { io.KeyShift = false; } break; case 17: { io.KeyCtrl = false; } break; } }); window->on_mouse_down.AddListener([](xe::ui::MouseEvent* e) { auto& io = ImGui::GetIO(); io.MousePos = ImVec2(float(e->x()), float(e->y())); switch (e->button()) { case xe::ui::MouseEvent::Button::kLeft: { io.MouseDown[0] = true; } break; case xe::ui::MouseEvent::Button::kRight: { io.MouseDown[1] = true; } break; } }); window->on_mouse_move.AddListener([](xe::ui::MouseEvent* e) { auto& io = ImGui::GetIO(); io.MousePos = ImVec2(float(e->x()), float(e->y())); }); window->on_mouse_up.AddListener([](xe::ui::MouseEvent* e) { auto& io = ImGui::GetIO(); io.MousePos = ImVec2(float(e->x()), float(e->y())); switch (e->button()) { case xe::ui::MouseEvent::Button::kLeft: { io.MouseDown[0] = false; } break; case xe::ui::MouseEvent::Button::kRight: { io.MouseDown[1] = false; } break; } }); window->on_mouse_wheel.AddListener([](xe::ui::MouseEvent* e) { auto& io = ImGui::GetIO(); io.MousePos = ImVec2(float(e->x()), float(e->y())); io.MouseWheel += float(e->dy() / 120.0f); }); window->on_painting.AddListener([&](xe::ui::UIEvent* e) { auto& io = ImGui::GetIO(); auto current_tick_count = Clock::QueryHostTickCount(); static uint64_t last_draw_tick_count = 0; io.DeltaTime = (current_tick_count - last_draw_tick_count) / static_cast(Clock::host_tick_frequency()); last_draw_tick_count = current_tick_count; io.DisplaySize = ImVec2(static_cast(window->width()), static_cast(window->height())); ImGui::NewFrame(); ImGui::ShowTestWindow(); ImGui::ShowMetricsWindow(); ImGui::Render(); // Continuous paint. window->Invalidate(); }); // Wait until we are exited. loop->AwaitQuit(); imgui_drawer_.reset(); window.reset(); loop.reset(); Profiler::Dump(); Profiler::Shutdown(); return 0; } } // namespace ui } // namespace xe