Replies: 2 comments
-
@kajmaj87 #include <ftxui/component/component.hpp>
#include <ftxui/dom/elements.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <array>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <chrono>
#include <mach/mach_time.h>
using namespace ftxui;
std::string get_timestamp(const std::string &file_path) {
auto t {std::chrono::system_clock::now()};
auto tt {std::chrono::system_clock::to_time_t(t)};
std::stringstream ss;
ss << file_path << "/" << "info" << std::put_time(std::localtime(&tt), "%y%m%d_%H%M%S") << ".log";
return ss.str();
}
class Interval
{
private:
unsigned int initial_;
public:
// Ctor
inline Interval() : initial_(mach_absolute_time())
{
}
// Dtor
virtual ~Interval()
{
}
inline unsigned int value() const
{
return mach_absolute_time() - initial_;
}
};
class Fps
{
protected:
unsigned int m_fps;
unsigned int m_fpscount;
Interval m_fpsinterval;
public:
// Constructor
Fps() : m_fps(0), m_fpscount(0)
{
}
// Update
void update()
{
// increase the counter by one
++m_fpscount;
// one second elapsed? (= 1000 milliseconds)
if (m_fpsinterval.value() > 24000000) // modified this to be in ballpark of CPU freq on M1
{
// save the current counter value to m_fps
m_fps = m_fpscount;
// reset the counter and the interval
m_fpscount = 0;
m_fpsinterval = Interval();
}
}
// Get fps
unsigned int get() const
{
return m_fps;
}
};
int main() {
auto screen {ScreenInteractive::Fullscreen()};
auto fps {Fps()};
auto path {""};
std::ofstream log(get_timestamp(path));
if (not log.is_open()) {
throw std::runtime_error("Failed to create log file!");
}
auto log_it {[&](const auto &msg) {
// log << msg << '\n';
}};
std::thread stream_thread;
std::string thread_id;
std::atomic<bool> stream_stop;
std::vector<std::string> all_entries;
std::mutex entry_lock;
int last_entry {0};
auto my_event {Event::Special("update_stream")};
std::string fps_string;
auto is_streaming {[&] {
if (stream_stop) {
return thread_id + ": Stopped";
}
return thread_id + ": Running";
}};
auto start_stream {[&] {
constexpr auto shell_cmd {"i=0; while true; do d=$(date); echo [""$i""] [""$d""] [""$(openssl rand -hex 20)""]; i=$(( i + 1 )); sleep 0.5; done;"};
stream_thread = std::thread([&] {
log_it("Starting thread");
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(shell_cmd, "r"), pclose);
if (not pipe) {
throw std::runtime_error("popen() failed!");
}
std::array<char, 128> buffer {};
std::string line {};
stream_stop = false;
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
log_it("Trying to fill buffer");
line += buffer.data();
if (line.back() == '\n') {
log_it("Buffer is full");
all_entries.emplace_back(line);
screen.PostEvent(my_event);
log_it(fps.get());
fps_string = std::to_string(fps.get());
entry_lock.lock();
++last_entry;
entry_lock.unlock();
line.clear();
buffer.fill('\0');
}
if (stream_stop) {
log_it("Stream stopped");
return;
}
}
});
log_it("Getting stream id");
auto id {stream_thread.get_id()};
log_it(id);
std::stringstream ss;
ss << id;
thread_id = ss.str();
stream_thread.detach();
}};
auto stop_stream {[&stream_stop] {
stream_stop = true;
}};
auto stream_buttons_container {Container::Horizontal({
Button("Start Stream", [&start_stream] {
start_stream();
}),
Button("Stop Stream", [&stop_stream] {
stop_stream();
}),
Button("Get FPS", [&] {
log_it(fps.get());
fps_string = std::to_string(fps.get());
})
})};
auto stream_buttons_renderer {Renderer(stream_buttons_container, [&] {
log_it("Rendering buttons");
return stream_buttons_container->Render() | center;
})};
auto stream_entries_container {Menu(&all_entries, &last_entry)};
auto stream_entries_renderer {Renderer(stream_entries_container, [&] {
log_it("Rendering entries");
return vbox({
stream_entries_container->Render(),
text("") | focus
}) | frame | yflex | border;
})};
auto stream_view_container {Container::Vertical({
stream_buttons_renderer,
stream_entries_renderer
})};
auto main_renderer {Renderer(stream_view_container, [&] {
fps.update();
log_it("Rendering main");
return vbox({
hcenter(bold(text("Stream View"))),
separator(),
hbox({
text(is_streaming()),
text("FPS: " + fps_string) | center | flex,
text(std::string("Entries: ") + std::to_string(all_entries.size()))
}),
stream_view_container->Render()
});
})};
log_it("Starting loop");
screen.Loop(main_renderer);
return EXIT_SUCCESS;
} The FPS was calculated based on the how often the screen loop ran the main renderer. Not perfect, but good experimentation for me. @ArthurSonzogni |
Beta Was this translation helpful? Give feedback.
-
FTXUI draws a new frame only when needed. If you popuplate yourself some event, then the number of frame drawn will constantly increase. FTXUI/examples/component/menu_underline_animated_gallery.cpp Lines 39 to 41 in d924143 See live demo of the above code. One thing to note: When there are many events queued, FTXUI will first handle all of them before drawing a new frame. It means drawing will never be a bottleneck. To count FPS maybe you can take some inspiration for the CppBestPractice game jam:
@matthesoundman An FPS counter sounds a bit too specific for becoming part of FTXUI. I am planning to add a section for third-party component/tools around FTXUI. Maybe this can be listed. |
Beta Was this translation helpful? Give feedback.
-
I'm updating my screen from a different thread using a custom event as mentioned in the docus. I would like to somehow establish the refresh rate and count how many fps I could do. Any tips on a way on how to measure the time it took to render a frame after the event has been sent?
Beta Was this translation helpful? Give feedback.
All reactions