mirror of
https://github.com/orange-cpp/omath.git
synced 2026-04-18 17:03:27 +00:00
Merge pull request #166 from orange-cpp/feature/hud_improvement
Feature/hud improvement
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
//
|
||||
// Created by Orange on 11/11/2024.
|
||||
//
|
||||
|
||||
#include "main_window.hpp"
|
||||
#include "omath/hud/renderer_realizations/imgui_renderer.hpp"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <algorithm>
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
@@ -20,6 +18,10 @@ namespace imgui_desktop::gui
|
||||
if (!glfwInit())
|
||||
std::exit(EXIT_FAILURE);
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, true);
|
||||
m_window = glfwCreateWindow(width, height, caption.data(), nullptr, nullptr);
|
||||
|
||||
@@ -27,84 +29,184 @@ namespace imgui_desktop::gui
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = {0.f, 0.f, 0.f, 0.f};
|
||||
|
||||
ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = {0.05f, 0.05f, 0.05f, 0.92f};
|
||||
ImGui::GetStyle().AntiAliasedLines = false;
|
||||
ImGui::GetStyle().AntiAliasedFill = false;
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(m_window, true);
|
||||
ImGui_ImplOpenGL3_Init("#version 130");
|
||||
ImGui_ImplOpenGL3_Init("#version 150");
|
||||
}
|
||||
|
||||
void MainWindow::Run()
|
||||
{
|
||||
omath::Color box_color = {0.f, 0.f, 0.f, 1.f};
|
||||
omath::Color box_fill = {0.f, 0.f, 0.f, 0.f};
|
||||
omath::Color bar_color = {0.f, 1.f, 0.f, 1.f};
|
||||
omath::Color bar_bg_color = {0.f, 0.f, 0.f, 0.0f};
|
||||
omath::Color bar_outline_color = {0.f, 0.f, 0.f, 1.f};
|
||||
float bar_width = 3.f;
|
||||
float bar_value = 1.f;
|
||||
|
||||
while (!glfwWindowShouldClose(m_window) && m_opened)
|
||||
{
|
||||
glfwPollEvents();
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::GetBackgroundDrawList()->AddRectFilled({}, ImGui::GetMainViewport()->Size, ImColor(40, 40, 40, 200));
|
||||
const auto* vp = ImGui::GetMainViewport();
|
||||
ImGui::GetBackgroundDrawList()->AddRectFilled({}, vp->Size, ImColor(30, 30, 30, 220));
|
||||
|
||||
ImGui::Begin("OHUD Showcase", &m_opened,
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration);
|
||||
{
|
||||
ImGui::SetWindowPos({});
|
||||
ImGui::SetWindowSize(ImGui::GetMainViewport()->Size);
|
||||
draw_controls();
|
||||
draw_overlay();
|
||||
|
||||
ImGui::ColorEdit4("Box", reinterpret_cast<float*>(&box_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::ColorEdit4("Box fill", reinterpret_cast<float*>(&box_fill), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::ColorEdit4("Bar", reinterpret_cast<float*>(&bar_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::ColorEdit4("Bar Background", reinterpret_cast<float*>(&bar_bg_color),
|
||||
ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::ColorEdit4("Bar Outline", reinterpret_cast<float*>(&bar_outline_color),
|
||||
ImGuiColorEditFlags_NoInputs);
|
||||
|
||||
ImGui::PushItemWidth(100.f);
|
||||
ImGui::SliderFloat("Bar Width", &bar_width, 1.f, 20.f);
|
||||
ImGui::SliderFloat("Bar Value", &bar_value, 0.f, 1.f);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
omath::hud::EntityOverlay ent({400.f, 100.f}, {400.f, 400.f}, std::make_shared<omath::hud::ImguiHudRenderer>());
|
||||
|
||||
ent.add_2d_box(box_color, box_fill, 1.f);
|
||||
ent.add_cornered_2d_box(omath::Color::from_rgba(255, 0, 255, 255), box_fill);
|
||||
ent.add_right_bar(bar_color, bar_outline_color, bar_bg_color, bar_width, bar_value);
|
||||
ent.add_left_bar(bar_color, bar_outline_color, bar_bg_color, bar_width, bar_value);
|
||||
ent.add_top_bar(bar_color, bar_outline_color, bar_bg_color, bar_width, bar_value);
|
||||
ent.add_right_label({0.f, 1.f, 0.f, 1.f}, 3, true, "Health: {}/100", 100);
|
||||
ent.add_right_label({1.f, 0.f, 0.f, 1.f}, 3, true, "Shield: {}/125", 125);
|
||||
ent.add_right_label({1.f, 0.f, 1.f, 1.f}, 3, true, "*LOCKED*");
|
||||
|
||||
ent.add_top_label(omath::Color::from_rgba(255, 255, 0, 255), 3, true, "*SCOPED*");
|
||||
ent.add_top_label(omath::Color::from_rgba(255, 0, 0, 255), 3, true, "*BLEEDING*");
|
||||
ent.add_snap_line(omath::Vector2<float>{400, 600}, omath::Color::from_rgba(255, 0, 0, 255), 2.f);
|
||||
ImGui::Render();
|
||||
|
||||
int display_w, display_h;
|
||||
|
||||
glfwGetFramebufferSize(m_window, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
glfwSwapBuffers(m_window);
|
||||
present();
|
||||
}
|
||||
glfwDestroyWindow(m_window);
|
||||
}
|
||||
|
||||
void MainWindow::draw_controls()
|
||||
{
|
||||
const auto* vp = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos({0.f, 0.f});
|
||||
ImGui::SetNextWindowSize({280.f, vp->Size.y});
|
||||
ImGui::Begin("Controls", &m_opened,
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
ImGui::PushItemWidth(160.f);
|
||||
|
||||
if (ImGui::CollapsingHeader("Entity", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::SliderFloat("X##ent", &m_entity_x, 100.f, vp->Size.x - 100.f);
|
||||
ImGui::SliderFloat("Top Y", &m_entity_top_y, 20.f, m_entity_bottom_y - 20.f);
|
||||
ImGui::SliderFloat("Bottom Y", &m_entity_bottom_y, m_entity_top_y + 20.f, vp->Size.y - 20.f);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Box", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::Checkbox("Box", &m_show_box); ImGui::SameLine();
|
||||
ImGui::Checkbox("Cornered", &m_show_cornered_box); ImGui::SameLine();
|
||||
ImGui::Checkbox("Dashed", &m_show_dashed_box);
|
||||
ImGui::ColorEdit4("Color##box", reinterpret_cast<float*>(&m_box_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::ColorEdit4("Fill##box", reinterpret_cast<float*>(&m_box_fill), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SliderFloat("Thickness", &m_box_thickness, 0.5f, 5.f);
|
||||
ImGui::SliderFloat("Corner ratio", &m_corner_ratio, 0.05f, 0.5f);
|
||||
ImGui::Separator();
|
||||
ImGui::ColorEdit4("Dash color", reinterpret_cast<float*>(&m_dash_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SliderFloat("Dash length", &m_dash_len, 2.f, 30.f);
|
||||
ImGui::SliderFloat("Dash gap", &m_dash_gap, 1.f, 20.f);
|
||||
ImGui::SliderFloat("Dash thick", &m_dash_thickness, 0.5f, 5.f);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Bars", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::ColorEdit4("Color##bar", reinterpret_cast<float*>(&m_bar_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::ColorEdit4("BG##bar", reinterpret_cast<float*>(&m_bar_bg_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::ColorEdit4("Outline##bar", reinterpret_cast<float*>(&m_bar_outline_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SliderFloat("Width##bar", &m_bar_width, 1.f, 20.f);
|
||||
ImGui::SliderFloat("Value##bar", &m_bar_value, 0.f, 1.f);
|
||||
ImGui::SliderFloat("Offset##bar", &m_bar_offset, 1.f, 20.f);
|
||||
ImGui::Checkbox("Right##bar", &m_show_right_bar); ImGui::SameLine();
|
||||
ImGui::Checkbox("Left##bar", &m_show_left_bar);
|
||||
ImGui::Checkbox("Top##bar", &m_show_top_bar); ImGui::SameLine();
|
||||
ImGui::Checkbox("Bottom##bar", &m_show_bottom_bar);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Labels", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::Checkbox("Outlined", &m_outlined);
|
||||
ImGui::SliderFloat("Offset##lbl", &m_label_offset, 0.f, 15.f);
|
||||
ImGui::Checkbox("Right##lbl", &m_show_right_labels); ImGui::SameLine();
|
||||
ImGui::Checkbox("Left##lbl", &m_show_left_labels);
|
||||
ImGui::Checkbox("Top##lbl", &m_show_top_labels); ImGui::SameLine();
|
||||
ImGui::Checkbox("Bottom##lbl", &m_show_bottom_labels);
|
||||
ImGui::Checkbox("Ctr top##lbl", &m_show_centered_top); ImGui::SameLine();
|
||||
ImGui::Checkbox("Ctr bot##lbl", &m_show_centered_bottom);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Skeleton"))
|
||||
{
|
||||
ImGui::Checkbox("Show##skel", &m_show_skeleton);
|
||||
ImGui::ColorEdit4("Color##skel", reinterpret_cast<float*>(&m_skel_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SliderFloat("Thick##skel", &m_skel_thickness, 0.5f, 5.f);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Snap Line"))
|
||||
{
|
||||
ImGui::Checkbox("Show##snap", &m_show_snap);
|
||||
ImGui::ColorEdit4("Color##snap", reinterpret_cast<float*>(&m_snap_color), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SliderFloat("Width##snap", &m_snap_width, 0.5f, 5.f);
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void MainWindow::draw_overlay()
|
||||
{
|
||||
const auto* vp = ImGui::GetMainViewport();
|
||||
|
||||
omath::hud::EntityOverlay ent(
|
||||
{m_entity_x, m_entity_top_y}, {m_entity_x, m_entity_bottom_y},
|
||||
std::make_shared<omath::hud::ImguiHudRenderer>());
|
||||
|
||||
draw_boxes(ent);
|
||||
draw_bars(ent);
|
||||
draw_labels(ent);
|
||||
|
||||
if (m_show_skeleton)
|
||||
ent.add_skeleton(m_skel_color, m_skel_thickness);
|
||||
if (m_show_snap)
|
||||
ent.add_snap_line({vp->Size.x / 2.f, vp->Size.y}, m_snap_color, m_snap_width);
|
||||
}
|
||||
|
||||
void MainWindow::draw_boxes(omath::hud::EntityOverlay& ent) const
|
||||
{
|
||||
if (m_show_box)
|
||||
ent.add_2d_box(m_box_color, m_box_fill, m_box_thickness);
|
||||
if (m_show_cornered_box)
|
||||
ent.add_cornered_2d_box(omath::Color::from_rgba(255, 0, 255, 255), m_box_fill, m_corner_ratio, m_box_thickness);
|
||||
if (m_show_dashed_box)
|
||||
ent.add_dashed_box(m_dash_color, m_dash_len, m_dash_gap, m_dash_thickness);
|
||||
}
|
||||
|
||||
void MainWindow::draw_bars(omath::hud::EntityOverlay& ent) const
|
||||
{
|
||||
if (m_show_right_bar)
|
||||
ent.add_right_bar(m_bar_color, m_bar_outline_color, m_bar_bg_color, m_bar_width, m_bar_value, m_bar_offset);
|
||||
if (m_show_left_bar)
|
||||
ent.add_left_bar(m_bar_color, m_bar_outline_color, m_bar_bg_color, m_bar_width, m_bar_value, m_bar_offset);
|
||||
if (m_show_top_bar)
|
||||
ent.add_top_bar(m_bar_color, m_bar_outline_color, m_bar_bg_color, m_bar_width, m_bar_value, m_bar_offset);
|
||||
if (m_show_bottom_bar)
|
||||
ent.add_bottom_bar(m_bar_color, m_bar_outline_color, m_bar_bg_color, m_bar_width, m_bar_value, m_bar_offset);
|
||||
}
|
||||
|
||||
void MainWindow::draw_labels(omath::hud::EntityOverlay& ent) const
|
||||
{
|
||||
if (m_show_right_labels)
|
||||
{
|
||||
ent.add_right_label({0.f, 1.f, 0.f, 1.f}, m_label_offset, m_outlined, "Health: {}/100", 100);
|
||||
ent.add_right_label({1.f, 0.f, 0.f, 1.f}, m_label_offset, m_outlined, "Shield: {}/125", 125);
|
||||
ent.add_right_label({1.f, 0.f, 1.f, 1.f}, m_label_offset, m_outlined, "*LOCKED*");
|
||||
}
|
||||
if (m_show_left_labels)
|
||||
{
|
||||
ent.add_left_label(omath::Color::from_rgba(255, 128, 0, 255), m_label_offset, m_outlined, "Armor: 75");
|
||||
ent.add_left_label(omath::Color::from_rgba(0, 200, 255, 255), m_label_offset, m_outlined, "Level: 42");
|
||||
}
|
||||
if (m_show_top_labels)
|
||||
{
|
||||
ent.add_top_label(omath::Color::from_rgba(255, 255, 0, 255), m_label_offset, m_outlined, "*SCOPED*");
|
||||
ent.add_top_label(omath::Color::from_rgba(255, 0, 0, 255), m_label_offset, m_outlined, "*BLEEDING*");
|
||||
}
|
||||
if (m_show_centered_top)
|
||||
ent.add_centered_top_label(omath::Color::from_rgba(0, 255, 255, 255), m_label_offset, m_outlined, "*VISIBLE*");
|
||||
if (m_show_centered_bottom)
|
||||
ent.add_centered_bottom_label(omath::Color::from_rgba(255, 255, 255, 255), m_label_offset, m_outlined, "PlayerName");
|
||||
if (m_show_bottom_labels)
|
||||
ent.add_bottom_label(omath::Color::from_rgba(200, 200, 0, 255), m_label_offset, m_outlined, "42m");
|
||||
}
|
||||
|
||||
void MainWindow::present()
|
||||
{
|
||||
int w, h;
|
||||
glfwGetFramebufferSize(m_window, &w, &h);
|
||||
glViewport(0, 0, w, h);
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
glfwSwapBuffers(m_window);
|
||||
}
|
||||
} // namespace imgui_desktop::gui
|
||||
// imgui_desktop
|
||||
@@ -1,11 +1,9 @@
|
||||
//
|
||||
// Created by Vlad on 6/17/2025.
|
||||
//
|
||||
|
||||
//
|
||||
// Created by Orange on 11/11/2024.
|
||||
//
|
||||
#pragma once
|
||||
#include <omath/hud/entity_overlay.hpp>
|
||||
#include <omath/utility/color.hpp>
|
||||
#include <string_view>
|
||||
|
||||
struct GLFWwindow;
|
||||
@@ -15,14 +13,57 @@ namespace imgui_desktop::gui
|
||||
class MainWindow
|
||||
{
|
||||
public:
|
||||
MainWindow(const std::string_view &caption, int width, int height);
|
||||
|
||||
MainWindow(const std::string_view& caption, int width, int height);
|
||||
void Run();
|
||||
|
||||
private:
|
||||
GLFWwindow* m_window;
|
||||
void draw_controls();
|
||||
void draw_overlay();
|
||||
void draw_boxes(omath::hud::EntityOverlay& ent) const;
|
||||
void draw_bars(omath::hud::EntityOverlay& ent) const;
|
||||
void draw_labels(omath::hud::EntityOverlay& ent) const;
|
||||
void present();
|
||||
|
||||
GLFWwindow* m_window = nullptr;
|
||||
static bool m_canMoveWindow;
|
||||
bool m_opened = true;
|
||||
|
||||
// Entity
|
||||
float m_entity_x = 550.f, m_entity_top_y = 150.f, m_entity_bottom_y = 450.f;
|
||||
|
||||
// Box
|
||||
omath::Color m_box_color{1.f, 1.f, 1.f, 1.f};
|
||||
omath::Color m_box_fill{0.f, 0.f, 0.f, 0.f};
|
||||
float m_box_thickness = 1.f, m_corner_ratio = 0.2f;
|
||||
bool m_show_box = true, m_show_cornered_box = true, m_show_dashed_box = false;
|
||||
|
||||
// Dashed box
|
||||
omath::Color m_dash_color = omath::Color::from_rgba(255, 200, 0, 255);
|
||||
float m_dash_len = 8.f, m_dash_gap = 5.f, m_dash_thickness = 1.f;
|
||||
|
||||
// Bars
|
||||
omath::Color m_bar_color{0.f, 1.f, 0.f, 1.f};
|
||||
omath::Color m_bar_bg_color{0.f, 0.f, 0.f, 0.5f};
|
||||
omath::Color m_bar_outline_color{0.f, 0.f, 0.f, 1.f};
|
||||
float m_bar_width = 4.f, m_bar_value = 0.75f, m_bar_offset = 5.f;
|
||||
bool m_show_right_bar = true, m_show_left_bar = true;
|
||||
bool m_show_top_bar = true, m_show_bottom_bar = true;
|
||||
|
||||
// Labels
|
||||
float m_label_offset = 3.f;
|
||||
bool m_outlined = true;
|
||||
bool m_show_right_labels = true, m_show_left_labels = true;
|
||||
bool m_show_top_labels = true, m_show_bottom_labels = true;
|
||||
bool m_show_centered_top = true, m_show_centered_bottom = true;
|
||||
|
||||
// Skeleton
|
||||
omath::Color m_skel_color = omath::Color::from_rgba(255, 255, 255, 200);
|
||||
float m_skel_thickness = 1.f;
|
||||
bool m_show_skeleton = false;
|
||||
|
||||
// Snap line
|
||||
omath::Color m_snap_color = omath::Color::from_rgba(255, 50, 50, 255);
|
||||
float m_snap_width = 1.5f;
|
||||
bool m_show_snap = true;
|
||||
};
|
||||
} // gui
|
||||
// imgui_desktop
|
||||
} // namespace imgui_desktop::gui
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace omath::hud
|
||||
float ratio, float offset = 5.f);
|
||||
|
||||
void add_left_bar(const Color& color, const Color& outline_color, const Color& bg_color, float width,
|
||||
float ratio, float offset = 5.f) const;
|
||||
float ratio, float offset = 5.f);
|
||||
|
||||
template<typename... Args>
|
||||
void add_right_label(const Color& color, const float offset, const bool outlined,
|
||||
@@ -55,12 +55,64 @@ namespace omath::hud
|
||||
|
||||
void add_snap_line(const Vector2<float>& start_pos, const Color& color, float width);
|
||||
|
||||
void add_dashed_box(const Color& color, float dash_len = 8.f, float gap_len = 5.f,
|
||||
float thickness = 1.f) const;
|
||||
|
||||
void add_skeleton(const Color& color, float thickness = 1.f) const;
|
||||
|
||||
void add_bottom_bar(const Color& color, const Color& outline_color, const Color& bg_color, float height,
|
||||
float ratio, float offset = 5.f);
|
||||
|
||||
template<typename... Args>
|
||||
void add_bottom_label(const Color& color, const float offset, const bool outlined,
|
||||
std::format_string<Args...> fmt, Args&&... args)
|
||||
{
|
||||
const std::string label = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
add_bottom_label(color, offset, outlined, std::string_view{label});
|
||||
}
|
||||
|
||||
void add_bottom_label(const Color& color, float offset, bool outlined, std::string_view text);
|
||||
|
||||
template<typename... Args>
|
||||
void add_left_label(const Color& color, const float offset, const bool outlined,
|
||||
std::format_string<Args...> fmt, Args&&... args)
|
||||
{
|
||||
const std::string label = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
add_left_label(color, offset, outlined, std::string_view{label});
|
||||
}
|
||||
|
||||
void add_left_label(const Color& color, float offset, bool outlined, const std::string_view& text);
|
||||
|
||||
template<typename... Args>
|
||||
void add_centered_bottom_label(const Color& color, const float offset, const bool outlined,
|
||||
std::format_string<Args...> fmt, Args&&... args)
|
||||
{
|
||||
const std::string label = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
add_centered_bottom_label(color, offset, outlined, std::string_view{label});
|
||||
}
|
||||
|
||||
void add_centered_bottom_label(const Color& color, float offset, bool outlined, const std::string_view& text);
|
||||
|
||||
template<typename... Args>
|
||||
void add_centered_top_label(const Color& color, const float offset, const bool outlined,
|
||||
std::format_string<Args...> fmt, Args&&... args)
|
||||
{
|
||||
const std::string label = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
add_centered_top_label(color, offset, outlined, std::string_view{label});
|
||||
}
|
||||
|
||||
void add_centered_top_label(const Color& color, float offset, bool outlined, const std::string_view& text);
|
||||
|
||||
private:
|
||||
void draw_outlined_text(const Vector2<float>& position, const Color& color,
|
||||
const std::string_view& text);
|
||||
void draw_dashed_line(const Vector2<float>& from, const Vector2<float>& to, const Color& color,
|
||||
float dash_len, float gap_len, float thickness) const;
|
||||
CanvasBox m_canvas;
|
||||
Vector2<float> m_text_cursor_right;
|
||||
Vector2<float> m_text_cursor_top;
|
||||
Vector2<float> m_text_cursor_bottom;
|
||||
Vector2<float> m_text_cursor_left;
|
||||
std::shared_ptr<HudRendererInterface> m_renderer;
|
||||
};
|
||||
} // namespace omath::hud
|
||||
@@ -18,8 +18,7 @@ namespace omath::hud
|
||||
virtual void add_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color,
|
||||
float thickness) = 0;
|
||||
|
||||
virtual void add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color,
|
||||
float thickness) = 0;
|
||||
virtual void add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color) = 0;
|
||||
|
||||
virtual void add_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) = 0;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace omath::hud
|
||||
void add_line(const Vector2<float>& line_start, const Vector2<float>& line_end, const Color& color,
|
||||
float thickness) override;
|
||||
void add_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color, float thickness) override;
|
||||
void add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color, float thickness) override;
|
||||
void add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color) override;
|
||||
void add_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) override;
|
||||
void add_filled_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) override;
|
||||
void add_text(const Vector2<float>& position, const Color& color, const std::string_view& text) override;
|
||||
|
||||
@@ -10,7 +10,9 @@ namespace omath::hud
|
||||
const auto points = m_canvas.as_array();
|
||||
|
||||
m_renderer->add_polyline({points.data(), points.size()}, box_color, thickness);
|
||||
m_renderer->add_filled_polyline({points.data(), points.size()}, fill_color, thickness);
|
||||
|
||||
if (fill_color.value().w > 0.f)
|
||||
m_renderer->add_filled_polyline({points.data(), points.size()}, fill_color);
|
||||
}
|
||||
void EntityOverlay::add_cornered_2d_box(const Color& box_color, const Color& fill_color,
|
||||
const float corner_ratio_len, const float thickness) const
|
||||
@@ -65,7 +67,7 @@ namespace omath::hud
|
||||
m_text_cursor_right.x += offset + width;
|
||||
}
|
||||
void EntityOverlay::add_left_bar(const Color& color, const Color& outline_color, const Color& bg_color,
|
||||
const float width, float ratio, const float offset) const
|
||||
const float width, float ratio, const float offset)
|
||||
{
|
||||
ratio = std::clamp(ratio, 0.f, 1.f);
|
||||
const auto max_bar_height = std::abs(m_canvas.top_left_corner.y - m_canvas.bottom_right_corner.y);
|
||||
@@ -76,6 +78,8 @@ namespace omath::hud
|
||||
m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2<float>(width, -max_bar_height * ratio), color);
|
||||
m_renderer->add_rectangle(bar_start - Vector2<float>(1.f, 0.f),
|
||||
bar_start + Vector2<float>(width, -max_bar_height), outline_color);
|
||||
|
||||
m_text_cursor_left.x -= offset + width;
|
||||
}
|
||||
void EntityOverlay::add_right_label(const Color& color, const float offset, const bool outlined,
|
||||
const std::string_view& text)
|
||||
@@ -118,6 +122,95 @@ namespace omath::hud
|
||||
+ Vector2<float>{m_canvas.bottom_right_corner.x - m_canvas.bottom_left_corner.x, 0.f} / 2;
|
||||
m_renderer->add_line(start_pos, line_end, color, width);
|
||||
}
|
||||
void EntityOverlay::add_skeleton(const Color& color, const float thickness) const
|
||||
{
|
||||
// Maps normalized (rx in [0,1], ry in [0,1]) to canvas screen position
|
||||
const auto joint = [&](const float rx, const float ry) -> Vector2<float>
|
||||
{
|
||||
const auto top = m_canvas.top_left_corner
|
||||
+ (m_canvas.top_right_corner - m_canvas.top_left_corner) * rx;
|
||||
const auto bot = m_canvas.bottom_left_corner
|
||||
+ (m_canvas.bottom_right_corner - m_canvas.bottom_left_corner) * rx;
|
||||
return top + (bot - top) * ry;
|
||||
};
|
||||
|
||||
using B = std::pair<std::pair<float,float>, std::pair<float,float>>;
|
||||
static constexpr std::array<B, 15> k_bones{{
|
||||
// Spine
|
||||
{{0.50f, 0.13f}, {0.50f, 0.22f}}, // head → neck
|
||||
{{0.50f, 0.22f}, {0.50f, 0.38f}}, // neck → chest
|
||||
{{0.50f, 0.38f}, {0.50f, 0.55f}}, // chest → pelvis
|
||||
// Left arm
|
||||
{{0.50f, 0.22f}, {0.25f, 0.25f}}, // neck → L shoulder
|
||||
{{0.25f, 0.25f}, {0.13f, 0.42f}}, // L shoulder → L elbow
|
||||
{{0.13f, 0.42f}, {0.08f, 0.56f}}, // L elbow → L hand
|
||||
// Right arm
|
||||
{{0.50f, 0.22f}, {0.75f, 0.25f}}, // neck → R shoulder
|
||||
{{0.75f, 0.25f}, {0.87f, 0.42f}}, // R shoulder → R elbow
|
||||
{{0.87f, 0.42f}, {0.92f, 0.56f}}, // R elbow → R hand
|
||||
// Left leg
|
||||
{{0.50f, 0.55f}, {0.36f, 0.58f}}, // pelvis → L hip
|
||||
{{0.36f, 0.58f}, {0.32f, 0.77f}}, // L hip → L knee
|
||||
{{0.32f, 0.77f}, {0.27f, 0.97f}}, // L knee → L foot
|
||||
// Right leg
|
||||
{{0.50f, 0.55f}, {0.64f, 0.58f}}, // pelvis → R hip
|
||||
{{0.64f, 0.58f}, {0.68f, 0.77f}}, // R hip → R knee
|
||||
{{0.68f, 0.77f}, {0.73f, 0.97f}}, // R knee → R foot
|
||||
}};
|
||||
|
||||
for (const auto& [a, b] : k_bones)
|
||||
m_renderer->add_line(joint(a.first, a.second), joint(b.first, b.second), color, thickness);
|
||||
}
|
||||
|
||||
void EntityOverlay::draw_dashed_line(const Vector2<float>& from, const Vector2<float>& to, const Color& color,
|
||||
const float dash_len, const float gap_len, const float thickness) const
|
||||
{
|
||||
const auto total = (to - from).length();
|
||||
if (total <= 0.f)
|
||||
return;
|
||||
|
||||
const auto dir = (to - from).normalized();
|
||||
const float step = dash_len + gap_len;
|
||||
|
||||
const float n_dashes = std::floor((total + gap_len) / step);
|
||||
if (n_dashes < 1.f)
|
||||
return;
|
||||
|
||||
const float used = n_dashes * dash_len + (n_dashes - 1.f) * gap_len;
|
||||
const float offset = (total - used) / 2.f;
|
||||
|
||||
for (float i = 0.f; i < n_dashes; ++i)
|
||||
{
|
||||
const float pos = offset + i * step;
|
||||
const auto dash_start = from + dir * pos;
|
||||
const auto dash_end = from + dir * std::min(pos + dash_len, total);
|
||||
m_renderer->add_line(dash_start, dash_end, color, thickness);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOverlay::add_dashed_box(const Color& color, const float dash_len, const float gap_len,
|
||||
const float thickness) const
|
||||
{
|
||||
const float min_edge = std::min(
|
||||
(m_canvas.top_right_corner - m_canvas.top_left_corner).length(),
|
||||
(m_canvas.bottom_right_corner - m_canvas.top_right_corner).length());
|
||||
const float corner_len = std::min(dash_len, min_edge / 2.f);
|
||||
|
||||
const auto draw_edge = [&](const Vector2<float>& from, const Vector2<float>& to)
|
||||
{
|
||||
const auto dir = (to - from).normalized();
|
||||
|
||||
m_renderer->add_line(from, from + dir * corner_len, color, thickness);
|
||||
draw_dashed_line(from + dir * corner_len, to - dir * corner_len, color, dash_len, gap_len, thickness);
|
||||
m_renderer->add_line(to - dir * corner_len, to, color, thickness);
|
||||
};
|
||||
|
||||
draw_edge(m_canvas.top_left_corner, m_canvas.top_right_corner);
|
||||
draw_edge(m_canvas.top_right_corner, m_canvas.bottom_right_corner);
|
||||
draw_edge(m_canvas.bottom_right_corner,m_canvas.bottom_left_corner);
|
||||
draw_edge(m_canvas.bottom_left_corner, m_canvas.top_left_corner);
|
||||
}
|
||||
|
||||
void EntityOverlay::draw_outlined_text(const Vector2<float>& position, const Color& color,
|
||||
const std::string_view& text)
|
||||
{
|
||||
@@ -129,10 +222,84 @@ namespace omath::hud
|
||||
m_renderer->add_text(position + outline_offset, Color{0.f, 0.f, 0.f, 1.f}, text.data());
|
||||
m_renderer->add_text(position, color, text.data());
|
||||
}
|
||||
void EntityOverlay::add_bottom_bar(const Color& color, const Color& outline_color, const Color& bg_color,
|
||||
const float height, float ratio, const float offset)
|
||||
{
|
||||
ratio = std::clamp(ratio, 0.f, 1.f);
|
||||
const auto max_bar_width = std::abs(m_canvas.bottom_right_corner.x - m_canvas.bottom_left_corner.x);
|
||||
|
||||
const auto bar_start = m_canvas.bottom_left_corner + Vector2<float>{0.f, offset};
|
||||
m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2<float>(max_bar_width, height), bg_color);
|
||||
m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2<float>(max_bar_width * ratio, height), color);
|
||||
m_renderer->add_rectangle(bar_start, bar_start + Vector2<float>(max_bar_width, height), outline_color);
|
||||
|
||||
m_text_cursor_bottom.y += offset + height;
|
||||
}
|
||||
|
||||
void EntityOverlay::add_bottom_label(const Color& color, const float offset, const bool outlined,
|
||||
const std::string_view text)
|
||||
{
|
||||
const auto text_size = m_renderer->calc_text_size(text);
|
||||
|
||||
if (outlined)
|
||||
draw_outlined_text(m_text_cursor_bottom + Vector2<float>{0.f, offset}, color, text);
|
||||
else
|
||||
m_renderer->add_text(m_text_cursor_bottom + Vector2<float>{0.f, offset}, color, text);
|
||||
|
||||
m_text_cursor_bottom.y += text_size.y;
|
||||
}
|
||||
|
||||
void EntityOverlay::add_left_label(const Color& color, const float offset, const bool outlined,
|
||||
const std::string_view& text)
|
||||
{
|
||||
const auto text_size = m_renderer->calc_text_size(text);
|
||||
const auto pos = m_text_cursor_left + Vector2<float>{-(offset + text_size.x), 0.f};
|
||||
|
||||
if (outlined)
|
||||
draw_outlined_text(pos, color, text);
|
||||
else
|
||||
m_renderer->add_text(pos, color, text);
|
||||
|
||||
m_text_cursor_left.y += text_size.y;
|
||||
}
|
||||
|
||||
void EntityOverlay::add_centered_bottom_label(const Color& color, const float offset, const bool outlined,
|
||||
const std::string_view& text)
|
||||
{
|
||||
const auto text_size = m_renderer->calc_text_size(text);
|
||||
const auto box_center_x =
|
||||
m_canvas.bottom_left_corner.x + (m_canvas.bottom_right_corner.x - m_canvas.bottom_left_corner.x) / 2.f;
|
||||
const auto pos = Vector2<float>{box_center_x - text_size.x / 2.f, m_text_cursor_bottom.y + offset};
|
||||
|
||||
if (outlined)
|
||||
draw_outlined_text(pos, color, text);
|
||||
else
|
||||
m_renderer->add_text(pos, color, text);
|
||||
|
||||
m_text_cursor_bottom.y += text_size.y;
|
||||
}
|
||||
|
||||
void EntityOverlay::add_centered_top_label(const Color& color, const float offset, const bool outlined,
|
||||
const std::string_view& text)
|
||||
{
|
||||
const auto text_size = m_renderer->calc_text_size(text);
|
||||
const auto box_center_x =
|
||||
m_canvas.top_left_corner.x + (m_canvas.top_right_corner.x - m_canvas.top_left_corner.x) / 2.f;
|
||||
|
||||
m_text_cursor_top.y -= text_size.y;
|
||||
const auto pos = Vector2<float>{box_center_x - text_size.x / 2.f, m_text_cursor_top.y - offset};
|
||||
|
||||
if (outlined)
|
||||
draw_outlined_text(pos, color, text);
|
||||
else
|
||||
m_renderer->add_text(pos, color, text);
|
||||
}
|
||||
|
||||
EntityOverlay::EntityOverlay(const Vector2<float>& top, const Vector2<float>& bottom,
|
||||
const std::shared_ptr<HudRendererInterface>& renderer)
|
||||
: m_canvas(top, bottom), m_text_cursor_right(m_canvas.top_right_corner),
|
||||
m_text_cursor_top(m_canvas.top_left_corner), m_renderer(renderer)
|
||||
m_text_cursor_top(m_canvas.top_left_corner), m_text_cursor_bottom(m_canvas.bottom_left_corner),
|
||||
m_text_cursor_left(m_canvas.top_left_corner), m_renderer(renderer)
|
||||
{
|
||||
}
|
||||
} // namespace omath::hud
|
||||
@@ -22,15 +22,13 @@ namespace omath::hud
|
||||
{
|
||||
ImGui::GetBackgroundDrawList()->AddPolyline(reinterpret_cast<const ImVec2*>(vertexes.data()),
|
||||
static_cast<int>(vertexes.size()), color.to_im_color(),
|
||||
ImDrawFlags_None, thickness);
|
||||
ImDrawFlags_Closed, thickness);
|
||||
}
|
||||
|
||||
void ImguiHudRenderer::add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color,
|
||||
const float thickness)
|
||||
void ImguiHudRenderer::add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color)
|
||||
{
|
||||
ImGui::GetBackgroundDrawList()->AddPolyline(reinterpret_cast<const ImVec2*>(vertexes.data()),
|
||||
static_cast<int>(vertexes.size()), color.to_im_color(),
|
||||
ImDrawFlags_Closed, thickness);
|
||||
ImGui::GetBackgroundDrawList()->AddConvexPolyFilled(reinterpret_cast<const ImVec2*>(vertexes.data()),
|
||||
static_cast<int>(vertexes.size()), color.to_im_color());
|
||||
}
|
||||
|
||||
void ImguiHudRenderer::add_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color)
|
||||
@@ -50,7 +48,7 @@ namespace omath::hud
|
||||
text.data() + text.size());
|
||||
}
|
||||
[[nodiscard]]
|
||||
Vector2<float> calc_text_size(const std::string_view& text)
|
||||
Vector2<float> ImguiHudRenderer::calc_text_size(const std::string_view& text)
|
||||
{
|
||||
return Vector2<float>::from_im_vec2(ImGui::CalcTextSize(text.data()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user