in tools/k4aviewer/k4adevicedockcontrol.cpp [295:856]
K4ADockControlStatus K4ADeviceDockControl::Show()
{
std::stringstream labelBuilder;
labelBuilder << "Device S/N: " << m_deviceSerialNumber;
ImGui::Text("%s", labelBuilder.str().c_str());
ImGui::SameLine();
{
ImGuiExtensions::ButtonColorChanger cc(ImGuiExtensions::ButtonColor::Red);
if (ImGui::SmallButton("Close device"))
{
return K4ADockControlStatus::ShouldClose;
}
}
ImGui::Separator();
const bool deviceIsStarted = DeviceIsStarted();
// Check microphone health
//
if (m_microphone && m_microphone->GetStatusCode() != SoundIoErrorNone)
{
std::stringstream errorBuilder;
errorBuilder << "Microphone on device " << m_deviceSerialNumber << " failed!";
K4AViewerErrorManager::Instance().SetErrorStatus(errorBuilder.str());
StopMicrophone();
m_microphone->ClearStatusCode();
}
// Draw controls
//
// InputScalars are a bit wider than we want them by default.
//
constexpr float InputScalarScaleFactor = 0.5f;
bool depthEnabledStateChanged = ImGuiExtensions::K4ACheckbox("Enable Depth Camera",
&m_config.EnableDepthCamera,
!deviceIsStarted);
if (m_firstRun || depthEnabledStateChanged)
{
ImGui::SetNextTreeNodeOpen(m_config.EnableDepthCamera);
}
ImGui::Indent();
bool depthModeUpdated = depthEnabledStateChanged;
if (ImGui::TreeNode("Depth Configuration"))
{
const bool depthSettingsEditable = !deviceIsStarted && m_config.EnableDepthCamera;
auto *pDepthMode = reinterpret_cast<int *>(&m_config.DepthMode);
ImGui::Text("Depth mode");
depthModeUpdated |= ImGuiExtensions::K4ARadioButton("NFOV Binned",
pDepthMode,
K4A_DEPTH_MODE_NFOV_2X2BINNED,
depthSettingsEditable);
ImGui::SameLine();
depthModeUpdated |= ImGuiExtensions::K4ARadioButton("NFOV Unbinned ",
pDepthMode,
K4A_DEPTH_MODE_NFOV_UNBINNED,
depthSettingsEditable);
// New line
depthModeUpdated |= ImGuiExtensions::K4ARadioButton("WFOV Binned",
pDepthMode,
K4A_DEPTH_MODE_WFOV_2X2BINNED,
depthSettingsEditable);
ImGui::SameLine();
depthModeUpdated |= ImGuiExtensions::K4ARadioButton("WFOV Unbinned ",
pDepthMode,
K4A_DEPTH_MODE_WFOV_UNBINNED,
depthSettingsEditable);
// New line
depthModeUpdated |=
ImGuiExtensions::K4ARadioButton("Passive IR", pDepthMode, K4A_DEPTH_MODE_PASSIVE_IR, depthSettingsEditable);
ImGui::TreePop();
}
ImGui::Unindent();
bool colorEnableStateChanged = ImGuiExtensions::K4ACheckbox("Enable Color Camera",
&m_config.EnableColorCamera,
!deviceIsStarted);
if (m_firstRun || colorEnableStateChanged)
{
ImGui::SetNextTreeNodeOpen(m_config.EnableColorCamera);
}
ImGui::Indent();
bool colorResolutionUpdated = colorEnableStateChanged;
if (ImGui::TreeNode("Color Configuration"))
{
const bool colorSettingsEditable = !deviceIsStarted && m_config.EnableColorCamera;
bool colorFormatUpdated = false;
auto *pColorFormat = reinterpret_cast<int *>(&m_config.ColorFormat);
ImGui::Text("Format");
colorFormatUpdated |=
ImGuiExtensions::K4ARadioButton("BGRA", pColorFormat, K4A_IMAGE_FORMAT_COLOR_BGRA32, colorSettingsEditable);
ImGui::SameLine();
colorFormatUpdated |=
ImGuiExtensions::K4ARadioButton("MJPG", pColorFormat, K4A_IMAGE_FORMAT_COLOR_MJPG, colorSettingsEditable);
ImGui::SameLine();
colorFormatUpdated |=
ImGuiExtensions::K4ARadioButton("NV12", pColorFormat, K4A_IMAGE_FORMAT_COLOR_NV12, colorSettingsEditable);
ImGui::SameLine();
colorFormatUpdated |=
ImGuiExtensions::K4ARadioButton("YUY2", pColorFormat, K4A_IMAGE_FORMAT_COLOR_YUY2, colorSettingsEditable);
// Uncompressed formats are only supported at 720p.
//
const char *imageFormatHelpMessage = "Not supported in NV12 or YUY2 mode!";
const bool imageFormatSupportsHighResolution = m_config.ColorFormat != K4A_IMAGE_FORMAT_COLOR_NV12 &&
m_config.ColorFormat != K4A_IMAGE_FORMAT_COLOR_YUY2;
if (colorFormatUpdated || m_firstRun)
{
if (!imageFormatSupportsHighResolution)
{
m_config.ColorResolution = K4A_COLOR_RESOLUTION_720P;
}
}
auto *pColorResolution = reinterpret_cast<int *>(&m_config.ColorResolution);
ImGui::Text("Resolution");
ImGui::Indent();
ImGui::Text("16:9");
ImGui::Indent();
colorResolutionUpdated |= ImGuiExtensions::K4ARadioButton(" 720p",
pColorResolution,
K4A_COLOR_RESOLUTION_720P,
colorSettingsEditable);
ImGui::SameLine();
colorResolutionUpdated |= ImGuiExtensions::K4ARadioButton("1080p",
pColorResolution,
K4A_COLOR_RESOLUTION_1080P,
colorSettingsEditable &&
imageFormatSupportsHighResolution);
ImGuiExtensions::K4AShowTooltip(imageFormatHelpMessage, !imageFormatSupportsHighResolution);
// New line
colorResolutionUpdated |= ImGuiExtensions::K4ARadioButton("1440p",
pColorResolution,
K4A_COLOR_RESOLUTION_1440P,
colorSettingsEditable &&
imageFormatSupportsHighResolution);
ImGuiExtensions::K4AShowTooltip(imageFormatHelpMessage, !imageFormatSupportsHighResolution);
ImGui::SameLine();
colorResolutionUpdated |= ImGuiExtensions::K4ARadioButton("2160p",
pColorResolution,
K4A_COLOR_RESOLUTION_2160P,
colorSettingsEditable &&
imageFormatSupportsHighResolution);
ImGuiExtensions::K4AShowTooltip(imageFormatHelpMessage, !imageFormatSupportsHighResolution);
ImGui::Unindent();
ImGui::Text("4:3");
ImGui::Indent();
colorResolutionUpdated |= ImGuiExtensions::K4ARadioButton("1536p",
pColorResolution,
K4A_COLOR_RESOLUTION_1536P,
colorSettingsEditable &&
imageFormatSupportsHighResolution);
ImGuiExtensions::K4AShowTooltip(imageFormatHelpMessage, !imageFormatSupportsHighResolution);
ImGui::SameLine();
colorResolutionUpdated |= ImGuiExtensions::K4ARadioButton("3072p",
pColorResolution,
K4A_COLOR_RESOLUTION_3072P,
colorSettingsEditable &&
imageFormatSupportsHighResolution);
ImGuiExtensions::K4AShowTooltip(imageFormatHelpMessage, !imageFormatSupportsHighResolution);
ImGui::Unindent();
ImGui::Unindent();
ImGui::TreePop();
}
if (ImGui::TreeNode("Color Controls"))
{
// Some of the variable names in here are just long enough to cause clang-format to force a line-wrap,
// which causes half of these (very similar) calls to look radically different than the rest, which
// makes it harder to pick out similarities/differences at a glance, so turn off clang-format for this
// bit.
//
// clang-format off
const float SliderScaleFactor = 0.5f;
ShowColorControl(K4A_COLOR_CONTROL_EXPOSURE_TIME_ABSOLUTE, &m_colorSettingsCache.ExposureTimeUs,
[SliderScaleFactor](ColorSetting *cacheEntry) {
ColorControlAction result = ColorControlAction::None;
// Exposure time supported values are factors off 1,000,000 / 2, so we need an exponential control.
// There isn't one for ints, so we use the float control and make it look like an int control.
//
auto valueFloat = static_cast<float>(cacheEntry->Value);
ImGui::PushItemWidth(ImGui::CalcItemWidth() * SliderScaleFactor);
if (ImGuiExtensions::K4ASliderFloat("Exposure Time",
&valueFloat,
488.f,
1000000.f,
"%.0f us",
8.0f,
cacheEntry->Mode == K4A_COLOR_CONTROL_MODE_MANUAL))
{
result = ColorControlAction::SetManual;
cacheEntry->Value = static_cast<int32_t>(valueFloat);
}
ImGui::PopItemWidth();
ImGui::SameLine();
ShowColorControlAutoButton(cacheEntry->Mode, &result, "exposure");
return result;
});
ShowColorControl(K4A_COLOR_CONTROL_WHITEBALANCE, &m_colorSettingsCache.WhiteBalance,
[SliderScaleFactor](ColorSetting *cacheEntry) {
ColorControlAction result = ColorControlAction::None;
ImGui::PushItemWidth(ImGui::CalcItemWidth() * SliderScaleFactor);
if (ImGuiExtensions::K4ASliderInt("White Balance",
&cacheEntry->Value,
2500,
12500,
"%d K",
cacheEntry->Mode == K4A_COLOR_CONTROL_MODE_MANUAL))
{
result = ColorControlAction::SetManual;
// White balance must be stepped in units of 10 or the call to update the setting fails.
//
cacheEntry->Value -= cacheEntry->Value % 10;
}
ImGui::PopItemWidth();
ImGui::SameLine();
ShowColorControlAutoButton(cacheEntry->Mode, &result, "whitebalance");
return result;
});
ImGui::PushItemWidth(ImGui::CalcItemWidth() * SliderScaleFactor);
ShowColorControl(K4A_COLOR_CONTROL_BRIGHTNESS, &m_colorSettingsCache.Brightness,
[](ColorSetting *cacheEntry) {
return ImGui::SliderInt("Brightness", &cacheEntry->Value, 0, 255) ?
ColorControlAction::SetManual :
ColorControlAction::None;
});
ShowColorControl(K4A_COLOR_CONTROL_CONTRAST, &m_colorSettingsCache.Contrast,
[](ColorSetting *cacheEntry) {
return ImGui::SliderInt("Contrast", &cacheEntry->Value, 0, 10) ?
ColorControlAction::SetManual :
ColorControlAction::None;
});
ShowColorControl(K4A_COLOR_CONTROL_SATURATION, &m_colorSettingsCache.Saturation,
[](ColorSetting *cacheEntry) {
return ImGui::SliderInt("Saturation", &cacheEntry->Value, 0, 63) ?
ColorControlAction::SetManual :
ColorControlAction::None;
});
ShowColorControl(K4A_COLOR_CONTROL_SHARPNESS, &m_colorSettingsCache.Sharpness,
[](ColorSetting *cacheEntry) {
return ImGui::SliderInt("Sharpness", &cacheEntry->Value, 0, 4) ?
ColorControlAction::SetManual :
ColorControlAction::None;
});
ShowColorControl(K4A_COLOR_CONTROL_GAIN, &m_colorSettingsCache.Gain,
[](ColorSetting *cacheEntry) {
return ImGui::SliderInt("Gain", &cacheEntry->Value, 0, 255) ?
ColorControlAction::SetManual :
ColorControlAction::None;
});
ImGui::PopItemWidth();
ShowColorControl(K4A_COLOR_CONTROL_BACKLIGHT_COMPENSATION, &m_colorSettingsCache.BacklightCompensation,
[](ColorSetting *cacheEntry) {
return ImGui::Checkbox("Backlight Compensation", reinterpret_cast<bool *>(&cacheEntry->Value)) ?
ColorControlAction::SetManual :
ColorControlAction::None;
});
ShowColorControl(K4A_COLOR_CONTROL_POWERLINE_FREQUENCY, &m_colorSettingsCache.PowerlineFrequency,
[](ColorSetting *cacheEntry) {
ImGui::Text("Power Frequency");
ImGui::SameLine();
bool updated = false;
updated |= ImGui::RadioButton("50Hz", &cacheEntry->Value, 1);
ImGui::SameLine();
updated |= ImGui::RadioButton("60Hz", &cacheEntry->Value, 2);
return updated ? ColorControlAction::SetManual : ColorControlAction::None;
});
// clang-format on
if (ImGui::Button("Refresh"))
{
LoadColorSettingsCache();
}
ImGui::SameLine();
if (ImGui::Button("Reset to default##RGB"))
{
ApplyDefaultColorSettings();
}
ImGui::TreePop();
}
ImGui::Unindent();
if (colorResolutionUpdated || m_firstRun)
{
if (m_config.ColorResolution == K4A_COLOR_RESOLUTION_3072P)
{
// 4K supports up to 15FPS
//
m_config.Framerate = K4A_FRAMES_PER_SECOND_15;
}
}
if (depthModeUpdated || m_firstRun)
{
if (m_config.DepthMode == K4A_DEPTH_MODE_WFOV_UNBINNED)
{
m_config.Framerate = K4A_FRAMES_PER_SECOND_15;
}
}
const bool supports30fps = !(m_config.EnableColorCamera &&
m_config.ColorResolution == K4A_COLOR_RESOLUTION_3072P) &&
!(m_config.EnableDepthCamera && m_config.DepthMode == K4A_DEPTH_MODE_WFOV_UNBINNED);
const bool enableFramerate = !deviceIsStarted && (m_config.EnableColorCamera || m_config.EnableDepthCamera);
ImGui::Text("Framerate");
auto *pFramerate = reinterpret_cast<int *>(&m_config.Framerate);
bool framerateUpdated = false;
framerateUpdated |= ImGuiExtensions::K4ARadioButton("30 FPS",
pFramerate,
K4A_FRAMES_PER_SECOND_30,
enableFramerate && supports30fps);
ImGuiExtensions::K4AShowTooltip("Not supported with WFOV Unbinned or 3072p!", !supports30fps);
ImGui::SameLine();
framerateUpdated |=
ImGuiExtensions::K4ARadioButton("15 FPS", pFramerate, K4A_FRAMES_PER_SECOND_15, enableFramerate);
ImGui::SameLine();
framerateUpdated |= ImGuiExtensions::K4ARadioButton(" 5 FPS", pFramerate, K4A_FRAMES_PER_SECOND_5, enableFramerate);
ImGuiExtensions::K4ACheckbox("Disable streaming LED", &m_config.DisableStreamingIndicator, !deviceIsStarted);
ImGui::Separator();
const bool imuSupported = m_config.EnableColorCamera || m_config.EnableDepthCamera;
m_config.EnableImu &= imuSupported;
ImGuiExtensions::K4ACheckbox("Enable IMU", &m_config.EnableImu, !deviceIsStarted && imuSupported);
ImGuiExtensions::K4AShowTooltip("Not supported without at least one camera!", !imuSupported);
const bool synchronizedImagesAvailable = m_config.EnableColorCamera && m_config.EnableDepthCamera;
m_config.SynchronizedImagesOnly &= synchronizedImagesAvailable;
if (m_microphone)
{
ImGuiExtensions::K4ACheckbox("Enable Microphone", &m_config.EnableMicrophone, !deviceIsStarted);
}
else
{
m_config.EnableMicrophone = false;
ImGui::Text("Microphone not detected!");
}
ImGui::Separator();
if (ImGui::TreeNode("Internal Sync"))
{
ImGuiExtensions::K4ACheckbox("Synchronized images only",
&m_config.SynchronizedImagesOnly,
!deviceIsStarted && synchronizedImagesAvailable);
ImGui::PushItemWidth(ImGui::CalcItemWidth() * InputScalarScaleFactor);
constexpr int stepSize = 1;
const bool depthDelayUpdated = ImGuiExtensions::K4AInputScalar("Depth delay (us)",
ImGuiDataType_S32,
&m_config.DepthDelayOffColorUsec,
&stepSize,
nullptr,
"%d",
!deviceIsStarted);
if (framerateUpdated || depthDelayUpdated)
{
// InputScalar doesn't do bounds-checks, so we have to do it ourselves whenever
// the user interacts with the control
//
int maxDepthDelay = 0;
switch (m_config.Framerate)
{
case K4A_FRAMES_PER_SECOND_30:
maxDepthDelay = std::micro::den / 30;
break;
case K4A_FRAMES_PER_SECOND_15:
maxDepthDelay = std::micro::den / 15;
break;
case K4A_FRAMES_PER_SECOND_5:
maxDepthDelay = std::micro::den / 5;
break;
default:
throw std::logic_error("Invalid framerate!");
}
m_config.DepthDelayOffColorUsec = std::max(m_config.DepthDelayOffColorUsec, -maxDepthDelay);
m_config.DepthDelayOffColorUsec = std::min(m_config.DepthDelayOffColorUsec, maxDepthDelay);
}
ImGui::PopItemWidth();
ImGui::TreePop();
}
if (m_firstRun && (m_syncInConnected || m_syncOutConnected))
{
ImGui::SetNextTreeNodeOpen(true);
}
if (ImGui::TreeNode("External Sync"))
{
ImGui::Text("Sync cable state");
ImGuiExtensions::K4ARadioButton("In", m_syncInConnected, false);
ImGui::SameLine();
ImGuiExtensions::K4ARadioButton("Out", m_syncOutConnected, false);
ImGui::SameLine();
if (ImGui::Button("Refresh"))
{
RefreshSyncCableStatus();
}
const char *syncModesSupportedTooltip = "Requires at least one camera and a connected sync cable!";
const bool syncModesSupported = (m_syncInConnected || m_syncOutConnected) &&
(m_config.EnableColorCamera || m_config.EnableDepthCamera);
if (!syncModesSupported)
{
m_config.WiredSyncMode = K4A_WIRED_SYNC_MODE_STANDALONE;
}
auto *pSyncMode = reinterpret_cast<int *>(&m_config.WiredSyncMode);
ImGuiExtensions::K4ARadioButton("Standalone", pSyncMode, K4A_WIRED_SYNC_MODE_STANDALONE, !deviceIsStarted);
ImGui::SameLine();
ImGuiExtensions::K4ARadioButton("Master",
pSyncMode,
K4A_WIRED_SYNC_MODE_MASTER,
!deviceIsStarted && syncModesSupported);
ImGuiExtensions::K4AShowTooltip(syncModesSupportedTooltip, !syncModesSupported);
ImGui::SameLine();
ImGuiExtensions::K4ARadioButton("Sub",
pSyncMode,
K4A_WIRED_SYNC_MODE_SUBORDINATE,
!deviceIsStarted && syncModesSupported);
ImGuiExtensions::K4AShowTooltip(syncModesSupportedTooltip, !syncModesSupported);
constexpr int stepSize = 1;
ImGui::PushItemWidth(ImGui::CalcItemWidth() * InputScalarScaleFactor);
ImGuiExtensions::K4AInputScalar("Delay off master (us)",
ImGuiDataType_U32,
&m_config.SubordinateDelayOffMasterUsec,
&stepSize,
nullptr,
"%d",
!deviceIsStarted);
ImGui::PopItemWidth();
ImGui::TreePop();
}
ImGui::Separator();
if (ImGui::TreeNode("Device Firmware Version Info"))
{
k4a_hardware_version_t versionInfo = m_device.get_version();
ImGui::Text("RGB camera: %u.%u.%u", versionInfo.rgb.major, versionInfo.rgb.minor, versionInfo.rgb.iteration);
ImGui::Text("Depth camera: %u.%u.%u",
versionInfo.depth.major,
versionInfo.depth.minor,
versionInfo.depth.iteration);
ImGui::Text("Audio: %u.%u.%u", versionInfo.audio.major, versionInfo.audio.minor, versionInfo.audio.iteration);
ImGui::Text("Build Config: %s", versionInfo.firmware_build == K4A_FIRMWARE_BUILD_RELEASE ? "Release" : "Debug");
ImGui::Text("Signature type: %s",
versionInfo.firmware_signature == K4A_FIRMWARE_SIGNATURE_MSFT ?
"Microsoft" :
versionInfo.firmware_signature == K4A_FIRMWARE_SIGNATURE_TEST ? "Test" : "Unsigned");
ImGui::TreePop();
}
ImGui::Separator();
if (ImGuiExtensions::K4AButton("Restore", !deviceIsStarted))
ApplyDefaultConfiguration();
ImGui::SameLine();
if (ImGuiExtensions::K4AButton("Save", !deviceIsStarted))
SaveDefaultConfiguration();
ImGui::SameLine();
if (ImGuiExtensions::K4AButton("Reset", !deviceIsStarted))
ResetDefaultConfiguration();
const bool enableCameras = m_config.EnableColorCamera || m_config.EnableDepthCamera;
const ImVec2 buttonSize{ 275, 0 };
if (!deviceIsStarted)
{
ImGuiExtensions::ButtonColorChanger colorChanger(ImGuiExtensions::ButtonColor::Green);
const bool validStartMode = enableCameras || m_config.EnableMicrophone || m_config.EnableImu;
if (m_config.WiredSyncMode == K4A_WIRED_SYNC_MODE_SUBORDINATE)
{
ImGuiExtensions::TextColorChanger cc(ImGuiExtensions::TextColor::Warning);
ImGui::TextUnformatted("You are starting in subordinate mode.");
ImGui::TextUnformatted("The camera will not start until it");
ImGui::TextUnformatted("receives a start signal from the");
ImGui::TextUnformatted("master device");
}
if (ImGuiExtensions::K4AButton("Start", buttonSize, validStartMode))
{
Start();
}
}
else
{
ImGuiExtensions::ButtonColorChanger colorChanger(ImGuiExtensions::ButtonColor::Red);
if (ImGuiExtensions::K4AButton("Stop", buttonSize))
{
Stop();
}
ImGui::Separator();
const bool pointCloudViewerAvailable = m_config.EnableDepthCamera &&
m_config.DepthMode != K4A_DEPTH_MODE_PASSIVE_IR && m_camerasStarted;
K4AWindowSet::ShowModeSelector(&m_currentViewType,
true,
pointCloudViewerAvailable,
[this](K4AWindowSet::ViewType t) { return this->SetViewType(t); });
if (m_paused)
{
ImGuiExtensions::ButtonColorChanger cc(ImGuiExtensions::ButtonColor::Green);
if (ImGui::Button("Resume", buttonSize))
{
m_paused = false;
}
}
else
{
ImGuiExtensions::ButtonColorChanger cc(ImGuiExtensions::ButtonColor::Yellow);
if (ImGui::Button("Pause", buttonSize))
{
m_paused = true;
}
}
}
m_firstRun = false;
return K4ADockControlStatus::Ok;
}