62 if (width <= 0 || height <= 0)
64 std::cerr <<
"Warning: Attempted to create FBO with invalid dimensions: " << width <<
"x" << height << std::endl;
80 GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr));
81 GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
82 GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
83 GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
84 GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
85 GLCall(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
map_fbo->textureID, 0));
91 GLCall(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height));
92 GLCall(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
map_fbo->rboID));
94 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
96 std::cerr <<
"ERROR::FRAMEBUFFER:: Framebuffer is not complete! Status: " << glCheckFramebufferStatus(GL_FRAMEBUFFER) << std::endl;
99 GLCall(glBindFramebuffer(GL_FRAMEBUFFER, 0));
147 using clock = std::chrono::steady_clock;
148 static clock::time_point s_last = clock::now();
151 constexpr auto kInterval = std::chrono::minutes(1);
152 const auto now = clock::now();
153 if (now - s_last < kInterval)
175 if (gametable_entity.is_valid())
180 catch (
const std::exception& e)
183 err += std::string(
"GameTable: ") + e.what();
188 err +=
"GameTable: unknown error";
197 if (gametable_entity.is_valid())
199 auto game_table_name = gametable_entity.get<
GameTable>()->gameTableName;
209 err +=
"BoardManager missing";
212 catch (
const std::exception& e)
217 err += std::string(
"Board: ") + e.what();
224 err +=
"Board: unknown error";
250 glfwMakeContextCurrent(
window);
256 glfwSetWindowSizeLimits(
window, minWidth, minHeight, GLFW_DONT_CARE, GLFW_DONT_CARE);
259 glfwMaximizeWindow(
window);
261 std::cout << glGetString(GL_VERSION) << std::endl;
263 GLCall(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
264 GLCall(glEnable(GL_BLEND));
265 GLCall(glDisable(GL_DEPTH_TEST));
273 float positions[] = {
274 0.5f, 0.5f, 1.0f, 1.0f,
275 0.5f, -0.5f, 1.0f, 0.0f,
276 -0.5f, -0.5f, 0.0f, 0.0f,
277 -0.5f, 0.5f, 0.0f, 1.0f
280 unsigned int indices[] = {
288 layout.
Push<
float>(2);
289 layout.Push<
float>(2);
290 va.AddBuffer(vb, layout);
294 glm::mat4 proj = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f);
295 glm::mat4 identity = glm::mat4(1.0f);
299 Shader shader(shader_path.string());
300 Shader grid_shader(grid_shader_path.string());
303 grid_shader.SetUniformMat4f(
"projection", proj);
304 grid_shader.SetUniformMat4f(
"view", identity);
305 grid_shader.SetUniformMat4f(
"model", identity);
306 grid_shader.SetUniform1i(
"grid_type", 0);
307 grid_shader.SetUniform1f(
"cell_size", 1.0f);
308 grid_shader.SetUniform2f(
"grid_offset", 1.0f, 1.0f);
309 grid_shader.SetUniform1f(
"opacity", 1.0f);
312 shader.SetUniform1i(
"u_Texture", 0);
313 shader.SetUniformMat4f(
"projection", proj);
314 shader.SetUniformMat4f(
"view", identity);
315 shader.SetUniformMat4f(
"model", identity);
316 shader.SetUniform1i(
"u_UseTexture", 1);
317 shader.SetUniform1f(
"u_Alpha", 0.5f);
326 IMGUI_CHECKVERSION();
327 ImGui::CreateContext();
328 ImGuiIO& io = ImGui::GetIO();
330 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
331 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
332 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
333 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
335 io.ConfigWindowsMoveFromTitleBarOnly =
true;
338 ImGui::StyleColorsDark();
340 ImGuiStyle& style = ImGui::GetStyle();
341 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
343 style.WindowRounding = 0.0f;
344 style.Colors[ImGuiCol_WindowBg].w = 0.0f;
347 const char* glsl_version =
"#version 330 core";
348 ImGui_ImplGlfw_InitForOpenGL(
window,
true);
349 ImGui_ImplOpenGL3_Init();
352 while (!glfwWindowShouldClose(
window))
362 GLCall(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
363 GLCall(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
366 ImGui_ImplOpenGL3_NewFrame();
367 ImGui_ImplGlfw_NewFrame();
382 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
384 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
386 GLFWwindow* backup_current_context = glfwGetCurrentContext();
387 ImGui::UpdatePlatformWindows();
388 ImGui::RenderPlatformWindowsDefault();
389 glfwMakeContextCurrent(backup_current_context);
399 glfwDestroyWindow(
window);
406 auto dockspace_id = ImGui::GetID(
"Root");
407 ImGuiViewport* viewport = ImGui::GetMainViewport();
411 ImGui::DockBuilderRemoveNode(dockspace_id);
412 ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_PassthruCentralNode);
413 ImGui::DockBuilderSetNodeSize(dockspace_id, viewport->Size);
414 ImGui::DockBuilderSetNodePos(dockspace_id, viewport->Pos);
415 ImGuiID dock_panel_id;
416 ImGuiID dock_right_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right, 0.3f,
nullptr, &dock_panel_id);
418 ImGui::DockBuilderDockWindow(
"MapWindow", dock_panel_id);
419 ImGui::DockBuilderDockWindow(
"ChatWindow", dock_right_id);
420 ImGui::DockBuilderDockWindow(
"MarkerDiretory", dock_right_id);
421 ImGui::DockBuilderFinish(dockspace_id);
424 ImGuiWindowFlags root_flags = ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoFocusOnAppearing
425 | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoBringToFrontOnFocus;
426 ImGui::SetNextWindowPos({viewport->Pos.x, viewport->Pos.y + ImGui::GetFrameHeight()}, ImGuiCond_Always);
427 ImGui::SetNextWindowSize({viewport->Size.x, viewport->Size.y - ImGui::GetFrameHeight()}, ImGuiCond_Always);
428 ImGui::Begin(
"RootWindow",
nullptr, root_flags);
429 ImGui::DockSpace(dockspace_id);
455 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar;
457 ImGui::SetNextWindowSizeConstraints(ImVec2(800, 600), ImVec2(FLT_MAX, FLT_MAX));
458 ImGui::Begin(
"MapWindow",
nullptr, window_flags);
459 auto is_map_window_hovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_RootAndChildWindows);
460 ImVec2 content_size = ImGui::GetContentRegionAvail();
462 if (content_size.x > 0 && content_size.y > 0)
464 ResizeMapFBO(
static_cast<int>(content_size.x),
static_cast<int>(content_size.y));
466 ImVec2 window_size = ImGui::GetWindowSize();
467 ImVec2 window_pos = ImGui::GetWindowPos();
473 ImGui::Image((
void*)(intptr_t)
map_fbo->textureID, content_size, ImVec2(0, 1), ImVec2(1, 0));
475 ImVec2 displayed_image_size = ImGui::GetItemRectSize();
477 ImVec2 image_min_screen_pos = ImGui::GetItemRectMin();
479 ImVec2 toolbar_cursor_pos_in_parent = ImVec2(image_min_screen_pos.x - window_pos.x,
480 image_min_screen_pos.y - window_pos.y);
483 ImGuiIO& io = ImGui::GetIO();
484 ImVec2 mouse_pos_global = ImGui::GetMousePos();
486 bool is_mouse_within_image_bounds = (mouse_pos_global.x >= image_min_screen_pos.x &&
487 mouse_pos_global.x < (image_min_screen_pos.x + displayed_image_size.x) &&
488 mouse_pos_global.y >= image_min_screen_pos.y &&
489 mouse_pos_global.y < (image_min_screen_pos.y + displayed_image_size.y));
490 game_table_manager->processMouseInput(is_mouse_within_image_bounds, is_map_window_hovered);
492 if (is_mouse_within_image_bounds)
503 DrawDebugCircle(mouse_pos_global,
false, IM_COL32(0, 255, 0, 150), 10.0f);
504 DrawDebugCircle(image_min_screen_pos,
false, IM_COL32(0, 255, 0, 255), 10.0f);
509 ImGui::SetCursorScreenPos(image_min_screen_pos);
510 ImGui::InvisibleButton(
"##MapDropArea", displayed_image_size);
512 if (ImGui::BeginDragDropTarget())
514 if (
const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(
"MARKER_IMAGE"))
520 game_table_manager->board_manager->createMarker(markerImage->filename, markerImage->textureID, world_position, markerImage->size);
522 ImGui::EndDragDropTarget();
534 bool open_host_gametable =
false;
535 bool open_manage_gametable =
false;
536 bool connect_to_gametable =
false;
537 bool close_current_gametable =
false;
539 bool open_network_center =
false;
540 bool open_username_change =
false;
542 bool open_create_board =
false;
543 bool close_current_board =
false;
544 bool load_active_board =
false;
546 bool open_remove_assets =
false;
551 ImGui::BeginMainMenuBar();
554 if (ImGui::BeginMenu(
"Game Table"))
556 if (ImGui::MenuItem(
"Host..."))
558 open_host_gametable =
true;
560 if (ImGui::MenuItem(
"Connect..."))
562 connect_to_gametable =
true;
564 if (ImGui::MenuItem(
"Manage..."))
566 open_manage_gametable =
true;
571 if (ImGui::MenuItem(
"Save"))
575 if (ImGui::MenuItem(
"Close"))
577 close_current_gametable =
true;
586 if (ImGui::BeginMenu(
"Network"))
588 if (ImGui::MenuItem(
"Network Center"))
590 open_network_center =
true;
593 if (ImGui::MenuItem(
"Change Username"))
595 open_username_change =
true;
604 if (ImGui::BeginMenu(
"Board"))
606 if (ImGui::MenuItem(
"Create"))
608 open_create_board =
true;
610 if (ImGui::MenuItem(
"Open"))
612 load_active_board =
true;
616 if (ImGui::MenuItem(
"Save"))
621 if (ImGui::MenuItem(
"Close"))
623 close_current_board =
true;
630 if (ImGui::BeginMenu(
"Notes"))
633 if (ImGui::MenuItem(
"Note Editor",
nullptr, vis))
639 if (ImGui::BeginMenu(
"Assets"))
641 if (ImGui::MenuItem(
"Add Marker (from file)"))
643 std::vector<std::filesystem::path> dst;
648 std::cerr <<
"Import marker failed: " << err <<
"\n";
656 if (ImGui::MenuItem(
"Add Map (from file)"))
658 std::vector<std::filesystem::path> dst;
663 std::cerr <<
"Import map failed: " << err <<
"\n";
671 if (ImGui::MenuItem(
"Remove Assets..."))
673 open_remove_assets =
true;
678 if (ImGui::BeginMenu(
"Help"))
680 if (ImGui::MenuItem(
"Guide"))
685 if (ImGui::MenuItem(
"About"))
691 if (ImGui::MenuItem(
"Console",
nullptr, vis))
699 ImGui::EndMainMenuBar();
703 if (open_remove_assets)
704 ImGui::OpenPopup(
"DeleteAssets");
705 if (ImGui::IsPopupOpen(
"DeleteAssets"))
708 if (open_host_gametable)
709 ImGui::OpenPopup(
"Host GameTable");
710 if (ImGui::IsPopupOpen(
"Host GameTable"))
713 if (open_manage_gametable)
714 ImGui::OpenPopup(
"Manage GameTables");
715 if (ImGui::IsPopupOpen(
"Manage GameTables"))
718 if (connect_to_gametable)
719 ImGui::OpenPopup(
"ConnectToGameTable");
720 if (ImGui::IsPopupOpen(
"ConnectToGameTable"))
723 if (close_current_gametable)
724 ImGui::OpenPopup(
"CloseGameTable");
725 if (ImGui::IsPopupOpen(
"CloseGameTable"))
728 if (open_network_center)
729 ImGui::OpenPopup(
"Network Center");
730 if (ImGui::IsPopupOpen(
"Network Center"))
733 if (open_username_change)
734 ImGui::OpenPopup(
"Change Username");
735 if (ImGui::IsPopupOpen(
"Change Username"))
738 if (open_create_board)
739 ImGui::OpenPopup(
"CreateBoard");
740 if (ImGui::IsPopupOpen(
"CreateBoard"))
743 if (load_active_board)
744 ImGui::OpenPopup(
"LoadBoard");
745 if (ImGui::IsPopupOpen(
"LoadBoard"))
748 if (close_current_board)
749 ImGui::OpenPopup(
"CloseBoard");
750 if (ImGui::IsPopupOpen(
"CloseBoard"))
754 ImGui::OpenPopup(
"Guide");
755 if (ImGui::IsPopupOpen(
"Guide"))
759 ImGui::OpenPopup(
"About");
760 if (ImGui::IsPopupOpen(
"About"))