69 std::thread run_thread;
70 std::thread py_thread;
71 if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
73 printf(
"Error: %s\n", SDL_GetError());
78 #if defined(IMGUI_IMPL_OPENGL_ES2)
80 const char *glsl_version =
"#version 100";
81 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
82 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
83 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
84 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
85 #elif defined(__APPLE__)
87 const char *glsl_version =
"#version 150";
88 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
89 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
90 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
91 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
94 const char *glsl_version =
"#version 130";
95 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
96 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
97 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
98 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
102 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
103 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
104 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
105 SDL_Window *window = SDL_CreateWindow(
"riCOM", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1200, 800, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);
108 std::cout <<
"Window could not be created! SDL Error: " << SDL_GetError() << std::endl;
110 SDL_GLContext gl_context = SDL_GL_CreateContext(window);
111 SDL_GL_MakeCurrent(window, gl_context);
112 SDL_GL_SetSwapInterval(1);
115 IMGUI_CHECKVERSION();
116 ImGui::CreateContext();
117 ImGuiIO &io = ImGui::GetIO();
120 mINI::INIFile ini_file(
"imgui.ini");
121 mINI::INIStructure ini_cfg;
122 ini_file.read(ini_cfg);
124 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
126 ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
127 ImGui_ImplOpenGL3_Init(glsl_version);
129 io.Fonts->AddFontFromMemoryCompressedTTF(KarlaRegular_compressed_data, KarlaRegular_compressed_size, 14.0f);
130 io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 14.0f);
131 io.Fonts->AddFontFromMemoryCompressedTTF(CousineRegular_compressed_data, CousineRegular_compressed_size, 14.0f);
132 io.Fonts->AddFontFromMemoryCompressedTTF(DroidSans_compressed_data, DroidSans_compressed_size, 14.0f);
133 io.Fonts->AddFontFromMemoryCompressedTTF(ProggyClean_compressed_data, ProggyClean_compressed_size, 14.0f);
134 io.Fonts->AddFontFromMemoryCompressedTTF(ProggyTiny_compressed_data, ProggyTiny_compressed_size, 14.0f);
136 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
137 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
141 ImVec2 uv_min = ImVec2(0.0f, 0.0f);
142 ImVec2 uv_max = ImVec2(1.0f, 1.0f);
143 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
144 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
146 ImVec2 menu_bar_size;
147 ImVec2 control_menu_size(200, 800);
149 const size_t n_textures = 16;
150 GLuint uiTextureIDs[n_textures];
151 glGenTextures(n_textures, uiTextureIDs);
153 for (
size_t i = 0; i < n_textures; i++)
155 glBindTexture(GL_TEXTURE_2D, uiTextureIDs[i]);
156 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
157 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
158 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
159 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
163 ImGui::FileBrowser openFileDialog;
164 openFileDialog.SetTitle(
"Open .mib or .t3p file");
165 openFileDialog.SetTypeFilters({
".mib",
".t3p",
".tpx3"});
166 ImGui::FileBrowser saveFileDialog(ImGuiFileBrowserFlags_EnterNewFilename | ImGuiFileBrowserFlags_CreateNewDir);
167 saveFileDialog.SetTitle(
"Save image as .png");
168 ImGui::FileBrowser saveDataDialog(ImGuiFileBrowserFlags_EnterNewFilename | ImGuiFileBrowserFlags_CreateNewDir);
169 saveDataDialog.SetTitle(
"Save COM data in binary format");
170 std::string filename =
"";
174 bool b_acq_open =
false;
175 bool b_started =
false;
176 bool b_file_selected =
false;
177 bool b_restarted =
false;
180 CheetahComm cheetah_comm;
194 std::string python_path;
198 python_path =
"python3";
210 const char *cmaps[] = {
"Parula",
"Heat",
"Jet",
"Turbo",
"Hot",
"Gray",
"Magma",
"Inferno",
"Plasma",
"Viridis",
"Cividis",
"Github",
"HSV"};
211 bool b_redraw =
false;
212 bool b_trigger_update =
false;
213 float menu_split_v = control_menu_size.y * 0.8f;
219 bool show_com_x =
false;
220 bool show_com_y =
false;
221 bool ricom_fft =
false;
222 bool vstem_fft =
false;
223 bool e_field_fft =
false;
225 std::map<std::string, ImGuiImageWindow<float>> generic_windows_f;
226 std::map<std::string, ImGuiImageWindow<std::complex<float>>> generic_windows_c;
228 generic_windows_f.emplace(
"RICOM-FFT",
ImGuiImageWindow<float>(
"RICOM-FFT", &uiTextureIDs[2],
false, 4, common_flags, &ricom_fft));
232 generic_windows_f.emplace(
"vSTEM-FFT",
ImGuiImageWindow<float>(
"vSTEM-FFT", &uiTextureIDs[4],
false, 4, common_flags, &vstem_fft));
235 generic_windows_f.emplace(
"COM-X",
ImGuiImageWindow<float>(
"RICOM-COMX", &uiTextureIDs[5],
true, 9, common_flags, &show_com_x));
236 generic_windows_f.emplace(
"COM-Y",
ImGuiImageWindow<float>(
"RICOM-COMY", &uiTextureIDs[6],
true, 9, common_flags, &show_com_y));
239 generic_windows_f.emplace(
"E-Field-FFT",
ImGuiImageWindow<float>(
"E-Field-FFT", &uiTextureIDs[8],
false, 4, common_flags, &e_field_fft));
246 ImGuiID dock_id = 3775;
248 static int drag_min_pos = 1;
255 while (SDL_PollEvent(&event))
257 ImGui_ImplSDL2_ProcessEvent(&event);
258 if (event.type == SDL_QUIT)
260 if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
265 ImGui_ImplOpenGL3_NewFrame();
266 ImGui_ImplSDL2_NewFrame();
270 if (ImGui::BeginMainMenuBar())
272 if (ImGui::BeginMenu(
"Appearance"))
274 ImGui::Combo(
"CBED Colormap", &ricom->
cbed_cmap, cmaps, IM_ARRAYSIZE(cmaps));
279 if (ImGui::BeginMenu(
"Hardware Settings"))
281 ImGui::Text(
"Plotting");
282 if (ImGui::DragInt(
"Image Refresh Interval [ms]", &ricom->
redraw_interval, 20, 10, 1000))
284 ini_cfg[
"Hardware"][
"Image Refresh Interval [ms]"] = std::to_string(ricom->
redraw_interval);
288 ImGui::Text(
"Multithreading");
291 ini_cfg[
"Hardware"][
"Threads"] = std::to_string(ricom->
n_threads);
293 if (ImGui::DragInt(
"Queue Size", &ricom->
queue_size, 1, 1, 256))
295 ini_cfg[
"Hardware"][
"Queue Size"] = std::to_string(ricom->
queue_size);
299 if (ImGui::BeginMenu(
"Imaging Modes"))
301 if (ImGui::Checkbox(
"Show riCOM", &ricom->
b_ricom))
312 if (ImGui::Checkbox(
"Show CoM-X", &show_com_x))
323 if (ImGui::Checkbox(
"Show CoM-Y", &show_com_y))
334 if (ImGui::Checkbox(
"Show E-Field", &ricom->
b_e_mag))
345 if (ImGui::Checkbox(
"View vSTEM Image", &ricom->
b_vSTEM))
358 menu_bar_size = ImGui::GetWindowSize();
359 ImGui::EndMainMenuBar();
362 const ImGuiViewport *viewport = ImGui::GetMainViewport();
376 ImVec2 pos = viewport->Pos;
377 pos[1] += menu_bar_size.y;
378 ImGui::SetNextWindowPos(pos);
380 control_menu_size.y = viewport->Size.y - menu_bar_size.y;
381 ImGui::SetNextWindowSize(control_menu_size);
382 ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1));
384 ImGui::Begin(
"Navigation", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar);
386 bool b_nx_changed =
false;
387 ImGui::BeginChild(
"Controls", ImVec2(0, menu_split_v),
false);
388 if (ImGui::CollapsingHeader(
"General Settings", ImGuiTreeNodeFlags_DefaultOpen))
390 ImGui::Text(
"Scan Area");
391 b_nx_changed = ImGui::DragInt(
"nx", &ricom->
nx, 1, 1, SDL_MAX_SINT32);
392 ImGui::DragInt(
"ny", &ricom->
ny, 1, 1, SDL_MAX_SINT32);
393 ImGui::DragInt(
"Repetitions", &ricom->
rep, 1, 1, SDL_MAX_SINT32);
395 ImGui::DragInt(
"skip row", &ricom->
skip_row, 1, 0, SDL_MAX_SINT32);
396 ImGui::DragInt(
"skip img", &ricom->
skip_img, 1, 0, SDL_MAX_SINT32);
398 if (ImGui::IsItemHovered())
400 ImGui::SetTooltip(
"Adjustments for Flyback time:\n skip row: skip n frames after each scan line\n skip img: skip n frames after each scan (when using repetitions)");
403 ImGui::Text(
"CBED Centre");
404 int *max_nx = &ricom->
n_cam;
405 bool offset_changed = ImGui::DragFloat2(
"Centre", &ricom->
offset[0], 0.1f, 0.0, (
float)*max_nx);
414 if (ImGui::CollapsingHeader(
"RICOM Settings", ImGuiTreeNodeFlags_DefaultOpen))
416 static int filter_max = 8;
417 static bool init_kernel_img =
true;
418 bool kernel_changed = ImGui::DragInt(
"Kernel Size", &ricom->
kernel.
kernel_size, 1, 1, 300);
421 bool rot_changed = ImGui::SliderFloat(
"Rotation", &ricom->
kernel.
rotation, 0.0f, 360.0f,
"%.1f deg");
422 bool filter_changed = ImGui::Checkbox(
"Use filter?", &ricom->
kernel.
b_filter);
424 if (init_kernel_img || rot_changed || kernel_changed || filter_changed || filter_changed2)
426 init_kernel_img =
false;
440 if (kernel_changed || b_nx_changed)
444 float sxk = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y * 3) / 2;
445 ImGui::Image((
void *)(intptr_t)uiTextureIDs[9], ImVec2(sxk, sxk), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f));
447 ImGui::Image((
void *)(intptr_t)uiTextureIDs[10], ImVec2(sxk, sxk), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f));
452 if (ImGui::CollapsingHeader(
"vSTEM Settings", ImGuiTreeNodeFlags_DefaultOpen))
454 bool inner_changed = ImGui::SliderFloat(
"Inner Radius", &ricom->
detector.
radius[0], 0.0f, 182.0f,
"%.1f px");
455 bool outer_changed = ImGui::SliderFloat(
"Outer Radius", &ricom->
detector.
radius[1], 0.0f, 182.0f,
"%.1f px");
456 if (inner_changed || outer_changed)
464 if (ImGui::CollapsingHeader(
"Stream reconstruction", ImGuiTreeNodeFlags_DefaultOpen)){
466 if (ImGui::Button(
"Preview", ImVec2(-1.0f, 0.0f)))
470 cheetah_comm.tpx3_det_config();
471 cheetah_comm.tpx3_cam_init();
472 cheetah_comm.tpx3_destination();
479 run_thread = std::thread(&
Ricom::run, ricom, 1);
481 std::this_thread::sleep_for(std::chrono::milliseconds(500));
482 cheetah_comm.start();
487 if (ImGui::Button(
"Acquire", ImVec2(-1.0f, 0.0f)))
491 cheetah_comm.tpx3_det_config();
492 cheetah_comm.tpx3_cam_init();
493 cheetah_comm.tpx3_destination();
495 run_thread = std::thread(&
Ricom::run, ricom, 1);
497 std::this_thread::sleep_for(std::chrono::milliseconds(500));
498 cheetah_comm.start();
502 if (ImGui::Button(
"Stop", ImVec2(-1.0f, 0.0f)))
510 ImGui::Checkbox(
"Cumulative Mode", &ricom->
b_cumulative);
515 if (ImGui::CollapsingHeader(
"File reconstruction", ImGuiTreeNodeFlags_DefaultOpen))
518 if (ImGui::Button(
"Open File", ImVec2(-1.0f, 0.0f)))
520 openFileDialog.Open();
523 openFileDialog.Display();
524 if (openFileDialog.HasSelected())
526 filename = openFileDialog.GetSelected().string();
527 b_file_selected =
true;
528 openFileDialog.ClearSelected();
534 ImGui::Text(
"File: %s", filename.c_str());
536 if (std::filesystem::path(filename).extension() ==
".t3p")
539 ImGui::DragInt(
"dwell time", &ricom->
dt, 1, 1);
541 else if (std::filesystem::path(filename).extension() ==
".tpx3")
544 if (ImGui::Button(
"Run File", ImVec2(-1.0f, 0.0f)))
546 run_thread = std::thread(&
Ricom::run, ricom, 0);
556 float panel_h_min = control_menu_size.y * 0.4;
557 float panel_h_max = control_menu_size.y - 32;
558 v_splitter(5, menu_split_v, panel_h_min, panel_h_max, pos.y + ImGui::GetStyle().ItemSpacing.y * 3);
560 ImGui::BeginChild(
"Progress", ImVec2(0, 0),
true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar);
561 ImGui::ProgressBar(ricom->
fr_count / (ricom->
fr_total), ImVec2(-1.0f, 0.0f));
562 ImGui::Text(
"Speed: %.2f kHz", ricom->
fr_freq);
563 if (ImGui::Button(
"Quit", ImVec2(-1.0f, 0.0f)))
572 ImGui::DockSpace(1319);
573 static auto first_time =
true;
577 ImGui::DockBuilderRemoveNode(1319);
578 ImGui::DockBuilderAddNode(1319, ImGuiDockNodeFlags_DockSpace);
579 ImGui::DockBuilderDockWindow(
"CBED", 1319);
580 ImGui::DockBuilderFinish(1319);
583 control_menu_size = ImGui::GetWindowSize();
586 main_dock.render(ImVec2(control_menu_size.x, pos.y), ImVec2(viewport->Size.x - control_menu_size.x, viewport->Size.y - menu_bar_size.y));
588 ImGui::Begin(
"CBED",
nullptr, ImGuiWindowFlags_NoScrollbar);
590 ImVec2 rem_space = ImGui::GetContentRegionAvail();
591 float tex_wh = (std::min)(rem_space.x, rem_space.y);
592 ImVec2 p = ImGui::GetCursorScreenPos();
594 float com_rel_x = p.x + tex_wh * (ricom->
com_public[0] / ricom->
n_cam);
595 float com_rel_y = p.y + tex_wh * (ricom->
com_public[1] / ricom->
n_cam);
597 float centre_x = p.x + tex_wh * (ricom->
offset[0] / ricom->
n_cam);
598 float centre_y = p.y + tex_wh * (ricom->
offset[1] / ricom->
n_cam);
600 com_rel_x = (std::max)(p.x, com_rel_x);
601 com_rel_y = (std::max)(p.y, com_rel_y);
602 com_rel_x = (std::min)(p.x + tex_wh, com_rel_x);
603 com_rel_y = (std::min)(p.y + tex_wh, com_rel_y);
605 float cross_width = tex_wh / 15.0f;
613 ImGui::Image((ImTextureID)uiTextureIDs[0], ImVec2(tex_wh, tex_wh), uv_min, uv_max, tint_col, border_col);
614 ImGui::GetWindowDrawList()->AddCircle(ImVec2(centre_x, centre_y), tex_wh * 0.03, IM_COL32(255, 255, 255, 255), 256);
615 ImGui::GetWindowDrawList()->AddLine(ImVec2(com_rel_x - cross_width, com_rel_y), ImVec2(com_rel_x + cross_width, com_rel_y), IM_COL32(255, 0, 0, 255), 1.5f);
616 ImGui::GetWindowDrawList()->AddLine(ImVec2(com_rel_x, com_rel_y - cross_width), ImVec2(com_rel_x, com_rel_y + cross_width), IM_COL32(255, 0, 0, 255), 1.5f);
619 ImGui::GetWindowDrawList()->AddCircle(ImVec2(centre_x, centre_y), tex_wh * (ricom->
detector.
radius[0] / ricom->
n_cam), IM_COL32(255, 50, 0, 255), 256);
620 ImGui::GetWindowDrawList()->AddCircle(ImVec2(centre_x, centre_y), tex_wh * (ricom->
detector.
radius[1] / ricom->
n_cam), IM_COL32(255, 150, 0, 255), 256);
626 ImVec2 pos_t = viewport->Pos;
627 pos_t[0] += control_menu_size[0] + 128;
628 pos_t[1] += menu_bar_size[1] + 128;
629 ImGui::SetNextWindowPos(pos_t, ImGuiCond_FirstUseEver);
630 ImVec2 size = {200, 400};
631 ImGui::SetNextWindowSize(size, ImGuiCond_FirstUseEver);
633 ImGui::Begin(
"Acquisition Header", &b_acq_open);
634 ImGui::BeginChild(
"Scrolling");
641 bool trigger = (b_trigger_update != ricom->
b_busy) && (ricom->
b_busy ==
false);
642 bool redraw_tick = (ricom->
b_busy && b_redraw && b_started);
643 update_views(generic_windows_f, ricom, b_restarted, trigger, redraw_tick);
644 update_views(generic_windows_c, ricom, b_restarted, trigger, redraw_tick);
647 b_trigger_update = ricom->
b_busy;
651 glViewport(0, 0, (
int)io.DisplaySize.x, (
int)io.DisplaySize.y);
652 glClear(GL_COLOR_BUFFER_BIT);
653 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
655 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
657 SDL_Window *backup_current_window = SDL_GL_GetCurrentWindow();
658 SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
659 ImGui::UpdatePlatformWindows();
660 ImGui::RenderPlatformWindowsDefault();
661 SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
664 SDL_GL_SwapWindow(window);
669 if (run_thread.joinable())
671 if (py_thread.joinable())
674 ImGui_ImplOpenGL3_Shutdown();
675 ImGui_ImplSDL2_Shutdown();
676 ImGui::DestroyContext();
678 SDL_GL_DeleteContext(gl_context);
679 SDL_DestroyWindow(window);
682 ini_file.write(ini_cfg,
true);
void v_splitter(float thickness, float &size0, const float &min_h, const float &max_h, const float &offset)
void bind_tex(SDL_Surface *srf, GLuint tex_id)
#define GENERIC_WINDOW_C(name)
#define GENERIC_WINDOW(name)
void update_views(std::map< std::string, ImGuiImageWindow< T >> &generic_windows_f, Ricom *ricom, bool b_restarted, bool trigger, bool b_redraw)
std::atomic< bool > report_set_public
std::array< float, 2 > radius
std::vector< float > f_approx
void approximate_frequencies(size_t n_im)
std::array< int, 2 > kernel_filter_frequency
std::vector< float > stem_image
std::vector< float > comy_image
std::array< float, 2 > com_public
bool b_recompute_detector
std::vector< float > comx_image
std::vector< std::complex< float > > e_field_data
ProgressMonitor * p_prog_mon
std::vector< float > ricom_image
std::array< float, 2 > offset
std::string connection_information
void check_ini_setting(mINI::INIStructure &ini_cfg, std::string section, std::string key, char *value)
bool ShowFontSelector(const char *label, int &selectedFont, mINI::INIStructure &ini_cfg)
bool ShowStyleSelector(const char *label, int &style_idx, mINI::INIStructure &ini_cfg)
void set_font(int font_idx)
void set_style(int style_idx)