kinect/codes/Azure-Kinect-Sensor-SDK/tools/k4aviewer/k4aviewer.cpp

324 lines
9.3 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Associated header
//
#include "k4aviewer.h"
// System headers
//
#include <fstream>
#include <sstream>
// Library headers
//
#include "k4aimgui_all.h"
// Project headers
//
#include "k4aaudiomanager.h"
#include "k4alogdockcontrol.h"
#include "k4asourceselectiondockcontrol.h"
#include "k4aviewererrormanager.h"
#include "k4aviewerutil.h"
#include "k4awindowmanager.h"
#include "perfcounter.h"
using namespace k4aviewer;
namespace
{
// Background color of app. Black.
//
const ImVec4 ClearColor(0.01f, 0.01f, 0.01f, 1.0f);
constexpr int GlfwFailureExitCode = -1;
constexpr float HighDpiScaleFactor = 2.0f;
void LogGlfwError(const int error, const char *msg)
{
std::ofstream errorLogger;
errorLogger.open("k4aviewer.err", std::ofstream::out | std::ofstream::app);
errorLogger << "Glfw error [" << error << "]: " << msg << std::endl;
errorLogger.close();
}
} // namespace
#ifdef DEBUG
#define K4AVIEWER_ENABLE_OPENGL_DEBUGGING
#endif
#ifdef K4AVIEWER_ENABLE_OPENGL_DEBUGGING
void APIENTRY glDebugOutput(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar *message,
void *userParam)
{
(void)userParam;
constexpr GLuint noisyMessages[] = {
131185, // Event that says a texture was loaded into memory
131169, // Event that says a buffer was allocated
};
for (GLuint noisyMessageId : noisyMessages)
{
if (id == noisyMessageId)
{
return;
}
}
std::ofstream msgLogger;
msgLogger.open("k4aviewer.log", std::ofstream::out | std::ofstream::app);
msgLogger << "OpenGL debug message:" << std::endl
<< " source: " << source << std::endl
<< " type: " << type << std::endl
<< " id: " << id << std::endl
<< " sev: " << severity << std::endl
<< " len: " << length << std::endl
<< " msg: " << message << std::endl
<< "---------------------------" << std::endl;
msgLogger.close();
}
#endif
K4AViewer::K4AViewer(const K4AViewerArgs &args)
{
// Setup window
glfwSetErrorCallback(LogGlfwError);
if (!glfwInit())
{
// Couldn't initialize the graphics library, which means we're not going to get far.
//
LogGlfwError(0, "glfwInit failed!");
exit(GlfwFailureExitCode);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
m_window = glfwCreateWindow(1440, 900, "Azure Kinect Viewer", nullptr, nullptr);
if (!m_window)
{
LogGlfwError(0, "glfwCreateWindow failed!");
exit(GlfwFailureExitCode);
}
glfwMakeContextCurrent(m_window);
glfwSwapInterval(1); // Enable vsync
gl3wInit();
#ifdef K4AVIEWER_ENABLE_OPENGL_DEBUGGING
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(glDebugOutput, nullptr);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
#endif
// Setup Dear ImGui binding
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui_ImplGlfw_InitForOpenGL(m_window, true);
ImGui_ImplOpenGL3_Init("#version 330");
// Setup style
ImGui::StyleColorsDark();
ImGui::GetStyle().WindowRounding = 0.0f;
// Disable saving window layout
ImGui::GetIO().IniFilename = nullptr;
if (args.HighDpi)
{
SetHighDpi();
}
const int audioInitStatus = K4AAudioManager::Instance().Initialize();
if (audioInitStatus != SoundIoErrorNone)
{
std::stringstream errorBuilder;
errorBuilder << "Failed to initialize audio backend: " << soundio_strerror(audioInitStatus) << "!";
K4AViewerErrorManager::Instance().SetErrorStatus(errorBuilder.str().c_str());
}
K4AWindowManager::Instance().PushLeftDockControl(std14::make_unique<K4ASourceSelectionDockControl>());
K4AWindowManager::Instance().PushBottomDockControl(std14::make_unique<K4ALogDockControl>());
}
K4AViewer::~K4AViewer()
{
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(m_window);
glfwTerminate();
}
void K4AViewer::Run()
{
while (!glfwWindowShouldClose(m_window))
{
glfwPollEvents();
// Start the ImGui frame
//
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ShowMainMenuBar();
K4AWindowManager::Instance().ShowAll();
ShowErrorOverlay();
if (m_showDemoWindow)
{
ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver);
ImGui::ShowDemoWindow(&m_showDemoWindow);
}
if (m_showStyleEditor)
{
ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver);
ImGui::Begin("Style editor", &m_showStyleEditor);
ImGui::ShowStyleEditor();
ImGui::End();
}
if (m_showMetricsWindow)
{
ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver);
ImGui::ShowMetricsWindow(&m_showMetricsWindow);
}
if (m_showPerfCounters)
{
ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver);
PerfCounterManager::ShowPerfWindow(&m_showPerfCounters);
}
// Finalize/render frame
//
ImGui::Render();
int displayW;
int displayH;
glfwMakeContextCurrent(m_window);
glfwGetFramebufferSize(m_window, &displayW, &displayH);
glViewport(0, 0, displayW, displayH);
K4AWindowManager::Instance().SetGLWindowSize(ImVec2(float(displayW), float(displayH)));
glClearColor(ClearColor.x, ClearColor.y, ClearColor.z, ClearColor.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(m_window);
}
}
void K4AViewer::ShowMainMenuBar()
{
if (ImGui::BeginMainMenuBar())
{
if (ImGui::BeginMenu("Settings"))
{
ShowViewerOptionMenuItem("Show log dock", ViewerOption::ShowLogDock);
ShowViewerOptionMenuItem("Show info overlay", ViewerOption::ShowInfoPane);
if (K4AViewerSettingsManager::Instance().GetViewerOption(ViewerOption::ShowInfoPane))
{
ShowViewerOptionMenuItem("Show framerate", ViewerOption::ShowFrameRateInfo);
}
ShowViewerOptionMenuItem("Show developer options", ViewerOption::ShowDeveloperOptions);
ImGui::Separator();
if (ImGui::MenuItem("Load default settings"))
{
K4AViewerSettingsManager::Instance().SetDefaults();
}
ImGui::Separator();
if (ImGui::MenuItem("Quit"))
{
glfwSetWindowShouldClose(m_window, true);
}
ImGui::EndMenu();
}
if (K4AViewerSettingsManager::Instance().GetViewerOption(ViewerOption::ShowDeveloperOptions))
{
if (ImGui::BeginMenu("Developer"))
{
ImGui::MenuItem("Show demo window", nullptr, &m_showDemoWindow);
ImGui::MenuItem("Show style editor", nullptr, &m_showStyleEditor);
ImGui::MenuItem("Show metrics window", nullptr, &m_showMetricsWindow);
ImGui::MenuItem("Show perf counters", nullptr, &m_showPerfCounters);
ImGui::EndMenu();
}
}
K4AWindowManager::Instance().SetMenuBarHeight(ImGui::GetWindowSize().y);
ImGui::EndMainMenuBar();
}
}
void K4AViewer::SetHighDpi()
{
ImGui::GetStyle().ScaleAllSizes(HighDpiScaleFactor);
// ImGui doesn't automatically scale fonts, so we have to do that ourselves
//
ImFontConfig fontConfig;
constexpr float defaultFontSize = 13.0f;
fontConfig.SizePixels = defaultFontSize * HighDpiScaleFactor;
ImGui::GetIO().Fonts->AddFontDefault(&fontConfig);
int w;
int h;
glfwGetWindowSize(m_window, &w, &h);
w = static_cast<int>(w * HighDpiScaleFactor);
h = static_cast<int>(h * HighDpiScaleFactor);
glfwSetWindowSize(m_window, w, h);
}
void K4AViewer::ShowErrorOverlay()
{
if (K4AViewerErrorManager::Instance().IsErrorSet())
{
constexpr char errorPopupTitle[] = "Error!";
ImGui::OpenPopup(errorPopupTitle);
ImGui::BeginPopupModal(errorPopupTitle, nullptr, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::Text("%s", K4AViewerErrorManager::Instance().GetErrorMessage().c_str());
if (ImGui::Button("Dismiss"))
{
K4AViewerErrorManager::Instance().PopError();
}
ImGui::EndPopup();
}
}
void K4AViewer::ShowViewerOptionMenuItem(const char *msg, ViewerOption option)
{
auto &settings = K4AViewerSettingsManager::Instance();
bool isSet = settings.GetViewerOption(option);
if (ImGui::MenuItem(msg, nullptr, isSet))
{
settings.SetViewerOption(option, !isSet);
}
}