diff --git a/Globals.cpp b/Globals.cpp index 556f2c4c..fee1d26d 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -713,6 +713,10 @@ global_settings::ConfigParse(cParser &Parser) { Parser.getTokens( 1 ); Parser >> extcam_cmd; } + else if( token == "extcam.rec" ) { + Parser.getTokens( 1 ); + Parser >> extcam_rec; + } else if( token == "extcam.res" ) { Parser.getTokens( 2 ); Parser >> extcam_res.x >> extcam_res.y; diff --git a/Globals.h b/Globals.h index 20ed16e4..cc8e19cb 100644 --- a/Globals.h +++ b/Globals.h @@ -192,6 +192,7 @@ struct global_settings { #ifdef USE_EXTCAM_CAMERA std::string extcam_cmd; + std::string extcam_rec; glm::ivec2 extcam_res{800, 600}; #endif diff --git a/driveruilayer.cpp b/driveruilayer.cpp index fad3977e..85d7e30c 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -63,6 +63,7 @@ void driver_ui::render_menu_contents() { ImGui::MenuItem(m_mappanel.name().c_str(), "Tab", &m_mappanel.is_open); ImGui::MenuItem(m_vehiclelist.name().c_str(), nullptr, &m_vehiclelist.is_open); ImGui::MenuItem(m_trainingcardpanel.name().c_str(), nullptr, &m_trainingcardpanel.is_open); + ImGui::MenuItem(m_cameraviewpanel.name().c_str(), nullptr, &m_cameraviewpanel.is_open); if (DebugModeFlag) ImGui::MenuItem(m_perfgraphpanel.name().c_str(), nullptr, &m_perfgraphpanel.is_open); @@ -226,9 +227,12 @@ driver_ui::set_cursor( bool const Visible ) { void driver_ui::render_() { const std::string *rec_name = m_trainingcardpanel.is_recording(); - if (rec_name && !m_cameraviewpanel.is_open) + if (rec_name && m_cameraviewpanel.set_state(ui::cameraview_panel::RECORDING)) { m_cameraviewpanel.rec_name = *rec_name; - m_cameraviewpanel.is_open = !!rec_name; + } else if (!rec_name && m_cameraviewpanel.is_open) + m_cameraviewpanel.set_state(ui::cameraview_panel::PREVIEW); + else if (!rec_name) + m_cameraviewpanel.set_state(ui::cameraview_panel::IDLE); // pause/quit modal auto const popupheader { STR_C("Simulation Paused") }; diff --git a/widgets/cameraview_extcam.cpp b/widgets/cameraview_extcam.cpp index a3ab8a5c..0d0a478b 100644 --- a/widgets/cameraview_extcam.cpp +++ b/widgets/cameraview_extcam.cpp @@ -27,31 +27,44 @@ ui::cameraview_panel::~cameraview_panel() { void ui::cameraview_panel::render() { - if (!is_open) { + if (!is_open && state != RECORDING) { exit_thread = true; - return; } + if (exit_thread) { + if (workthread.joinable()) + workthread.join(); + exit_thread = false; + if (state != IDLE && !Global.extcam_cmd.empty()) + workthread = std::thread(&cameraview_panel::workthread_func, this); + } + + if (!is_open) + return; + ImGui::SetNextWindowSizeConstraints(ImVec2(200, 200), ImVec2(2500, 2500), cameraview_window_callback); auto const panelname{(title.empty() ? m_name : title) + "###" + m_name}; - if (ImGui::Begin(panelname.c_str())) { + if (ImGui::Begin(panelname.c_str(), &is_open)) { render_contents(); } ImGui::End(); } +bool ui::cameraview_panel::set_state(state_e e) +{ + if (state != e) { + exit_thread = true; + state = e; + is_open = (state != IDLE); + return true; + } + return false; +} + void ui::cameraview_panel::render_contents() { - if (exit_thread) { - if (workthread.joinable()) - workthread.join(); - exit_thread = false; - if (!Global.extcam_cmd.empty()) - workthread = std::thread(&cameraview_panel::workthread_func, this); - } - if (!texture) { texture.emplace(); texture->make_stub(); @@ -89,6 +102,8 @@ void ui::cameraview_panel::render_contents() void ui::cameraview_panel::workthread_func() { std::string cmdline = Global.extcam_cmd; + if (state == RECORDING) + cmdline += " " + Global.extcam_rec; if (!rec_name.empty()) { const std::string magic{"{RECORD}"}; diff --git a/widgets/cameraview_extcam.h b/widgets/cameraview_extcam.h index d65a1213..469f590f 100644 --- a/widgets/cameraview_extcam.h +++ b/widgets/cameraview_extcam.h @@ -11,12 +11,22 @@ namespace ui { class cameraview_panel : public ui_panel { +public: + enum state_e { + IDLE, + PREVIEW, + RECORDING + }; + +private: std::atomic_bool exit_thread = true; std::thread workthread; uint8_t* image_ptr = nullptr; std::mutex mutex; + state_e state = IDLE; + std::optional texture; void workthread_func(); @@ -27,6 +37,7 @@ class cameraview_panel : public ui_panel void render() override; void render_contents() override; + bool set_state(state_e e); std::string rec_name; }; diff --git a/widgets/cameraview_vsdev.cpp b/widgets/cameraview_vsdev.cpp index f049a599..793bd5b7 100644 --- a/widgets/cameraview_vsdev.cpp +++ b/widgets/cameraview_vsdev.cpp @@ -46,6 +46,16 @@ void ui::cameraview_panel::render() ui_panel::render(); } +bool ui::cameraview_panel::set_state(state_e e) +{ + if (state != e) { + state = e; + is_open = (state != IDLE); + return true; + } + return false; +} + void ui::cameraview_panel::render_contents() { if (exit_thread) { diff --git a/widgets/cameraview_vsdev.h b/widgets/cameraview_vsdev.h index 639db877..d49b1798 100644 --- a/widgets/cameraview_vsdev.h +++ b/widgets/cameraview_vsdev.h @@ -7,6 +7,14 @@ namespace ui { class cameraview_panel : public ui_panel { +public: + enum state_e { + IDLE, + PREVIEW, + RECORDING + }; + +private: std::atomic_bool exit_thread = true; std::thread workthread; @@ -28,5 +36,6 @@ class cameraview_panel : public ui_panel void render() override; void render_contents() override; + bool set_state(state_e e); }; } // namespace ui