add implot and start using it
Some checks are pending
ContinuousDelivery / linux-ubuntu (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Waiting to run
ContinuousDelivery / windows (push) Waiting to run
ContinuousDelivery / windows-asan (push) Waiting to run
ContinuousDelivery / release (push) Blocked by required conditions
ContinuousIntegration / linux (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Waiting to run
ContinuousIntegration / macos (push) Waiting to run
ContinuousIntegration / windows (push) Waiting to run

This commit is contained in:
Green Sky 2025-01-22 19:03:10 +01:00
parent 6bd151e618
commit db0dffafd9
No known key found for this signature in database
12 changed files with 197 additions and 117 deletions

View File

@ -18,6 +18,7 @@ add_subdirectory(./solanaceae_tox)
add_subdirectory(./sdl) add_subdirectory(./sdl)
add_subdirectory(./imgui) add_subdirectory(./imgui)
add_subdirectory(./implot)
add_subdirectory(./stb) add_subdirectory(./stb)
add_subdirectory(./libwebp) add_subdirectory(./libwebp)

31
external/implot/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.24 FATAL_ERROR)
include(FetchContent)
if (NOT TARGET implot)
FetchContent_Declare(implot
GIT_REPOSITORY https://github.com/epezent/implot.git
GIT_TAG 47522f47054d33178e7defa780042bd2a06b09f9 # 22-01-2025
EXCLUDE_FROM_ALL
CONFIGURE_COMMAND "" # no cmake
)
FetchContent_GetProperties(implot)
if(NOT implot_POPULATED)
FetchContent_MakeAvailable(implot)
add_library(implot STATIC
${implot_SOURCE_DIR}/implot.h
${implot_SOURCE_DIR}/implot_internal.h
${implot_SOURCE_DIR}/implot.cpp
${implot_SOURCE_DIR}/implot_demo.cpp
${implot_SOURCE_DIR}/implot_items.cpp
)
target_include_directories(implot PUBLIC ${implot_SOURCE_DIR})
target_compile_features(implot PUBLIC cxx_std_11)
target_link_libraries(implot PUBLIC imgui)
#target_compile_definitions(implot PUBLIC IMGUI_USE_WCHAR32)
endif()
endif()

18
flake.lock generated
View File

@ -18,6 +18,23 @@
"type": "github" "type": "github"
} }
}, },
"implot": {
"flake": false,
"locked": {
"lastModified": 1737544983,
"narHash": "sha256-/hYfmkUa5zRb2iQHdw0FhNPBaUHqzEhA0lHDeNE8bkU=",
"owner": "epezent",
"repo": "implot",
"rev": "47522f47054d33178e7defa780042bd2a06b09f9",
"type": "github"
},
"original": {
"owner": "epezent",
"repo": "implot",
"rev": "47522f47054d33178e7defa780042bd2a06b09f9",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1720691131, "lastModified": 1720691131,
@ -54,6 +71,7 @@
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"implot": "implot",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nlohmann-json": "nlohmann-json", "nlohmann-json": "nlohmann-json",
"sdl3": "sdl3", "sdl3": "sdl3",

View File

@ -20,9 +20,13 @@
url = "github:libsdl-org/SDL_image/6f4584340b9b78542d11bf0232a1a0862de1f0a9"; url = "github:libsdl-org/SDL_image/6f4584340b9b78542d11bf0232a1a0862de1f0a9";
flake = false; flake = false;
}; };
implot = {
url = "github:epezent/implot/47522f47054d33178e7defa780042bd2a06b09f9";
flake = false;
};
}; };
outputs = { self, nixpkgs, flake-utils, nlohmann-json, sdl3, sdl3_image }: outputs = { self, nixpkgs, flake-utils, nlohmann-json, sdl3, sdl3_image, implot }:
flake-utils.lib.eachDefaultSystem (system: flake-utils.lib.eachDefaultSystem (system:
let let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs { inherit system; };
@ -91,13 +95,14 @@
#"-DCMAKE_C_FLAGS:STRING=-Og" #"-DCMAKE_C_FLAGS:STRING=-Og"
#"-DCMAKE_CXX_FLAGS:STRING=-Og" #"-DCMAKE_CXX_FLAGS:STRING=-Og"
"-DFETCHCONTENT_SOURCE_DIR_JSON=${nlohmann-json}" # we care about the version
# TODO: use package instead # TODO: use package instead
"-DFETCHCONTENT_SOURCE_DIR_JSON=${nlohmann-json}" # we care about the version
"-DFETCHCONTENT_SOURCE_DIR_ZSTD=${pkgs.zstd.src}" # we dont care about the version (we use 1.4.x features) "-DFETCHCONTENT_SOURCE_DIR_ZSTD=${pkgs.zstd.src}" # we dont care about the version (we use 1.4.x features)
"-DFETCHCONTENT_SOURCE_DIR_LIBWEBP=${pkgs.libwebp.src}" "-DFETCHCONTENT_SOURCE_DIR_LIBWEBP=${pkgs.libwebp.src}"
"-DFETCHCONTENT_SOURCE_DIR_SDL3=${sdl3}" "-DFETCHCONTENT_SOURCE_DIR_SDL3=${sdl3}"
"-DFETCHCONTENT_SOURCE_DIR_SDL3_IMAGE=${sdl3_image}" "-DFETCHCONTENT_SOURCE_DIR_SDL3_IMAGE=${sdl3_image}"
"-DSDLIMAGE_JXL=ON" "-DSDLIMAGE_JXL=ON"
"-DFETCHCONTENT_SOURCE_DIR_IMPLOT=${implot}" # could use pkgs.implot.src for outdated version
]; ];
# TODO: replace with install command # TODO: replace with install command

View File

@ -74,6 +74,7 @@ target_sources(tomato PUBLIC
./sys_tray.hpp ./sys_tray.hpp
./sys_tray.cpp ./sys_tray.cpp
./string_formatter_utils.hpp
./chat_gui/theme.hpp ./chat_gui/theme.hpp
./chat_gui/theme.cpp ./chat_gui/theme.cpp
./chat_gui/icons/direct.hpp ./chat_gui/icons/direct.hpp
@ -182,6 +183,7 @@ target_link_libraries(tomato PUBLIC
imgui imgui
imgui_backend_sdl3 imgui_backend_sdl3
imgui_backend_sdlrenderer3 imgui_backend_sdlrenderer3
implot
stb_image stb_image
stb_image_write stb_image_write

View File

@ -26,6 +26,8 @@
#include "./sdl_clipboard_utils.hpp" #include "./sdl_clipboard_utils.hpp"
#include "os_comps.hpp" #include "os_comps.hpp"
#include "./string_formatter_utils.hpp"
#include <cctype> #include <cctype>
#include <ctime> #include <ctime>
#include <cstdio> #include <cstdio>
@ -72,67 +74,6 @@ static constexpr float lerp(float a, float b, float t) {
return a + t * (b - a); return a + t * (b - a);
} }
// returns divider and places static suffix string into suffix_out
static int64_t sizeToHumanReadable(int64_t file_size, const char*& suffix_out) {
static const char* suffix_arr[] {
"Bytes",
"KiB",
"MiB",
"GiB",
"TiB",
"PiB",
// TODO: fix upper bound behaviour
};
int64_t divider = 1024;
for (size_t ij = 0; ij < std::size(suffix_arr); ij++, divider *= 1024) {
if (file_size < divider) {
suffix_out = suffix_arr[ij];
break;
}
}
return (divider > 1024) ? (divider / 1024) : 1;
}
// returns divider and places static suffix string into suffix_out
static int64_t durationToHumanReadable(int64_t t, const char*& suffix_out) {
static const char* suffix_arr[] {
"ms",
"s",
"min",
"h",
"d",
"a",
};
static const int64_t divider_arr[] {
1000, // ms -> s
60, // s -> min
60, // min -> h
24, // h -> d
256, // d -> a // aprox
};
if (t <= 0) {
suffix_out = suffix_arr[0];
return 1;
}
int64_t divider {1};
for (size_t i = 0; i < std::size(divider_arr); i++) {
if (t < divider * divider_arr[i]) {
suffix_out = suffix_arr[i];
return divider;
}
divider *= divider_arr[i];
}
// if we are here, we are in the last element
// 5 and 4
suffix_out = suffix_arr[5];
return divider;
}
static std::string file_path_url_escape(const std::string&& value) { static std::string file_path_url_escape(const std::string&& value) {
std::ostringstream escaped; std::ostringstream escaped;

View File

@ -4,6 +4,7 @@
#include <imgui/imgui.h> #include <imgui/imgui.h>
#include <imgui/backends/imgui_impl_sdl3.h> #include <imgui/backends/imgui_impl_sdl3.h>
#include <imgui/backends/imgui_impl_sdlrenderer3.h> #include <imgui/backends/imgui_impl_sdlrenderer3.h>
#include <implot.h>
#include "./theme.hpp" #include "./theme.hpp"
#include "./chat_gui/theme.hpp" #include "./chat_gui/theme.hpp"
@ -87,6 +88,7 @@ int main(int argc, char** argv) {
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImPlot::CreateContext();
// TODO: test android behaviour // TODO: test android behaviour
float display_scale = SDL_GetWindowDisplayScale(window.get()); float display_scale = SDL_GetWindowDisplayScale(window.get());
@ -238,6 +240,7 @@ int main(int argc, char** argv) {
ImGui_ImplSDLRenderer3_Shutdown(); ImGui_ImplSDLRenderer3_Shutdown();
ImGui_ImplSDL3_Shutdown(); ImGui_ImplSDL3_Shutdown();
ImPlot::DestroyContext();
ImGui::DestroyContext(); ImGui::DestroyContext();
renderer.reset(); renderer.reset();

View File

@ -9,6 +9,7 @@
#include "./frame_streams/sdl/sdl_video_frame_stream2.hpp" #include "./frame_streams/sdl/sdl_video_frame_stream2.hpp"
#include <imgui/imgui.h> #include <imgui/imgui.h>
#include <implot.h>
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
@ -123,6 +124,7 @@ MainScreen::MainScreen(SimpleConfigModel&& conf_, SDL_Renderer* renderer_, Theme
g_provideInstance("ImGuiMemUserData", ImGui::GetVersion(), "host", user_data); g_provideInstance("ImGuiMemUserData", ImGui::GetVersion(), "host", user_data);
} }
} }
g_provideInstance<ImPlotContext>("ImPlotContext", IMPLOT_VERSION, "host", ImPlot::GetCurrentContext());
g_provideInstance<TextureUploaderI>("TextureUploaderI", "host", &sdlrtu); g_provideInstance<TextureUploaderI>("TextureUploaderI", "host", &sdlrtu);
} }

View File

@ -0,0 +1,67 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <array>
// returns divider and places static suffix string into suffix_out
static int64_t sizeToHumanReadable(int64_t file_size, const char*& suffix_out) {
static const char* suffix_arr[] {
"Bytes",
"KiB",
"MiB",
"GiB",
"TiB",
"PiB",
// TODO: fix upper bound behaviour
};
int64_t divider = 1024;
for (size_t ij = 0; ij < std::size(suffix_arr); ij++, divider *= 1024) {
if (file_size < divider) {
suffix_out = suffix_arr[ij];
break;
}
}
return (divider > 1024) ? (divider / 1024) : 1;
}
// returns divider and places static suffix string into suffix_out
static int64_t durationToHumanReadable(int64_t t, const char*& suffix_out) {
static const char* suffix_arr[] {
"ms",
"s",
"min",
"h",
"d",
"a",
};
static const int64_t divider_arr[] {
1000, // ms -> s
60, // s -> min
60, // min -> h
24, // h -> d
256, // d -> a // aprox
};
if (t <= 0) {
suffix_out = suffix_arr[0];
return 1;
}
int64_t divider {1};
for (size_t i = 0; i < std::size(divider_arr); i++) {
if (t < divider * divider_arr[i]) {
suffix_out = suffix_arr[i];
return divider;
}
divider *= divider_arr[i];
}
// if we are here, we are in the last element
// 5 and 4
suffix_out = suffix_arr[5];
return divider;
}

View File

@ -1,6 +1,7 @@
#include "./tox_dht_cap_histo.hpp" #include "./tox_dht_cap_histo.hpp"
#include <imgui/imgui.h> #include <imgui/imgui.h>
#include <implot.h>
void ToxDHTCapHisto::tick(float time_delta) { void ToxDHTCapHisto::tick(float time_delta) {
if (!_enabled) { if (!_enabled) {
@ -54,8 +55,19 @@ void ToxDHTCapHisto::render(void) {
if (_show_window) { if (_show_window) {
if (ImGui::Begin("Tox DHT announce capability histogram", &_show_window)) { if (ImGui::Begin("Tox DHT announce capability histogram", &_show_window)) {
if (_enabled) { if (_enabled && ImPlot::BeginPlot("##caphisto")) {
ImGui::PlotHistogram("##histogram", _ratios.data(), _ratios.size(), 0, nullptr, 0.f, 1.f, {-1, -1}); ImPlot::SetupAxis(ImAxis_X1, "seconds", ImPlotAxisFlags_AutoFit);
ImPlot::SetupAxisLimits(ImAxis_Y1, 0, 1, ImPlotCond_Always);
// TODO: fix colors
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
ImPlot::PlotShaded("##ratio_shade", _ratios.data(), _ratios.size());
ImPlot::PopStyleVar();
ImPlot::PlotLine("##ratio", _ratios.data(), _ratios.size());
ImPlot::EndPlot();
} else { } else {
ImGui::TextUnformatted("logging disabled!"); ImGui::TextUnformatted("logging disabled!");
if (ImGui::Button("enable")) { if (ImGui::Button("enable")) {

View File

@ -1,7 +1,12 @@
#include "./tox_netprof_ui.hpp" #include "./tox_netprof_ui.hpp"
#include <imgui/imgui.h> #include <imgui/imgui.h>
#include <implot.h>
#include <string> #include <string>
#include <cmath>
#include "./string_formatter_utils.hpp"
static const char* typedPkgIDToString(Tox_Netprof_Packet_Type type, uint8_t id) { static const char* typedPkgIDToString(Tox_Netprof_Packet_Type type, uint8_t id) {
// pain // pain
@ -76,24 +81,6 @@ void ToxNetprofUI::tick(float time_delta) {
_time_since_last_add -= _value_add_interval; _time_since_last_add -= _value_add_interval;
} }
if (_udp_tctx.empty()) {
_udp_tctx.push_back(0.f);
_udp_tctx_prev = _tpi.toxNetprofGetPacketTotalCount(TOX_NETPROF_PACKET_TYPE_UDP, TOX_NETPROF_DIRECTION_SENT);
} else {
const auto new_value = _tpi.toxNetprofGetPacketTotalCount(TOX_NETPROF_PACKET_TYPE_UDP, TOX_NETPROF_DIRECTION_SENT);
_udp_tctx.push_back(new_value - _udp_tctx_prev);
_udp_tctx_prev = new_value;
}
if (_udp_tcrx.empty()) {
_udp_tcrx.push_back(0.f);
_udp_tcrx_prev = _tpi.toxNetprofGetPacketTotalCount(TOX_NETPROF_PACKET_TYPE_UDP, TOX_NETPROF_DIRECTION_RECV);
} else {
const auto new_value = _tpi.toxNetprofGetPacketTotalCount(TOX_NETPROF_PACKET_TYPE_UDP, TOX_NETPROF_DIRECTION_RECV);
_udp_tcrx.push_back(new_value - _udp_tcrx_prev);
_udp_tcrx_prev = new_value;
}
if (_udp_tbtx.empty()) { if (_udp_tbtx.empty()) {
_udp_tbtx.push_back(0.f); _udp_tbtx.push_back(0.f);
_udp_tbtx_prev = _tpi.toxNetprofGetPacketTotalBytes(TOX_NETPROF_PACKET_TYPE_UDP, TOX_NETPROF_DIRECTION_SENT); _udp_tbtx_prev = _tpi.toxNetprofGetPacketTotalBytes(TOX_NETPROF_PACKET_TYPE_UDP, TOX_NETPROF_DIRECTION_SENT);
@ -113,14 +100,6 @@ void ToxNetprofUI::tick(float time_delta) {
} }
// TODO: limit // TODO: limit
while (_udp_tctx.size() > 5*60) {
_udp_tctx.erase(_udp_tctx.begin());
}
while (_udp_tcrx.size() > 5*60) {
_udp_tcrx.erase(_udp_tcrx.begin());
}
while (_udp_tbtx.size() > 5*60) { while (_udp_tbtx.size() > 5*60) {
_udp_tbtx.erase(_udp_tbtx.begin()); _udp_tbtx.erase(_udp_tbtx.begin());
} }
@ -303,31 +282,54 @@ float ToxNetprofUI::render(float time_delta) {
} }
if (_show_window_histo) { if (_show_window_histo) {
if (ImGui::Begin("Tox Netprof histograms", &_show_window_histo)) { if (ImGui::Begin("Tox Netprof graph", &_show_window_histo)) {
if (_enabled) { if (_enabled && ImPlot::BeginPlot("##plot")) {
const float line_height = ImGui::GetTextLineHeight(); ImPlot::SetupAxes(nullptr, "bytes", ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit);
ImGui::PlotHistogram("udp total packets sent##histograms", _udp_tctx.data(), _udp_tctx.size(), 0, nullptr, 0.f, FLT_MAX, {0, 3*line_height});
ImGui::PlotHistogram("udp total packets received##histograms", _udp_tcrx.data(), _udp_tcrx.size(), 0, nullptr, 0.f, FLT_MAX, {0, 3*line_height});
std::string udp_tbtx_avg_str {"avg " + std::to_string(_udp_tbtx_avg) + " B/s"}; ImPlot::SetupAxisLimitsConstraints(ImAxis_Y1, 0.f, INFINITY);
ImGui::PlotHistogram(
"udp total bytes sent##histograms", // TODO: bytes tick interval of 1024 (or smaller like multiples of 2)
_udp_tbtx.data(), _udp_tbtx.size(), ImPlot::SetupAxisFormat(
0, ImAxis_Y1,
udp_tbtx_avg_str.c_str(), // TODO: extract
0.f, FLT_MAX, +[](double value, char* buff, int size, void*) -> int {
{0, 3*line_height} if (value < 0) {
return 0;
}
const char* byte_suffix = "???";
int64_t byte_divider = sizeToHumanReadable(value, byte_suffix);
return snprintf(buff, size, "%g %s/s", value/byte_divider, byte_suffix);
},
nullptr
); );
std::string udp_tbrx_avg_str {"avg " + std::to_string(_udp_tbrx_avg) + " B/s"}; {
ImGui::PlotHistogram( ImPlot::PlotLine(
"udp total bytes received##histograms", "udp tx/s",
_udp_tbrx.data(), _udp_tbrx.size(), _udp_tbtx.data(), _udp_tbtx.size(),
0, _value_add_interval // normalize to /s
udp_tbrx_avg_str.c_str(), );
0.f, FLT_MAX, auto item_color = ImPlot::GetLastItemColor();
{0, 3*line_height} item_color.w *= 0.5f;
); ImPlot::SetNextLineStyle(item_color);
ImPlot::PlotInfLines("udp tx avg", &_udp_tbtx_avg, 1, ImPlotInfLinesFlags_Horizontal);
}
{
ImPlot::PlotLine(
"udp rx/s",
_udp_tbrx.data(), _udp_tbrx.size(),
_value_add_interval // normalize to /s
);
auto item_color = ImPlot::GetLastItemColor();
item_color.w *= 0.5f;
ImPlot::SetNextLineStyle(item_color);
ImPlot::PlotInfLines("udp rx avg", &_udp_tbrx_avg, 1, ImPlotInfLinesFlags_Horizontal);
}
ImPlot::EndPlot();
} else { } else {
ImGui::TextUnformatted("logging disabled!"); ImGui::TextUnformatted("logging disabled!");
if (ImGui::Button("enable")) { if (ImGui::Button("enable")) {

View File

@ -34,12 +34,8 @@ class ToxNetprofUI {
std::map<uint8_t, float> _tcp_brx_heat; std::map<uint8_t, float> _tcp_brx_heat;
// histogram totals // histogram totals
uint64_t _udp_tctx_prev;
uint64_t _udp_tcrx_prev;
uint64_t _udp_tbtx_prev; uint64_t _udp_tbtx_prev;
uint64_t _udp_tbrx_prev; uint64_t _udp_tbrx_prev;
std::vector<float> _udp_tctx;
std::vector<float> _udp_tcrx;
std::vector<float> _udp_tbtx; std::vector<float> _udp_tbtx;
std::vector<float> _udp_tbrx; std::vector<float> _udp_tbrx;