Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
c966fc6954 | |||
d0761bf60e | |||
0f41ee6a2e | |||
0aeafec019 | |||
9a0df4f577 | |||
61714836bb | |||
cff0c100ec | |||
010c49d100 | |||
ff5dbaffc0 | |||
b56d581e4b | |||
aa661aaaa7 | |||
cc3f430bab | |||
139db5b03b | |||
7d0e5c80bd | |||
f716ad9dd1 | |||
671772a20e | |||
b0173f6d68 |
@ -2,3 +2,7 @@
|
||||
|
||||

|
||||
|
||||
## Highly experimental solanaceae client with Tox built-in
|
||||
|
||||

|
||||
|
||||
|
2
external/solanaceae_contact
vendored
2
external/solanaceae_contact
vendored
Submodule external/solanaceae_contact updated: 2d73c7272c...e40271670b
2
external/solanaceae_message3
vendored
2
external/solanaceae_message3
vendored
Submodule external/solanaceae_message3 updated: ab282235b5...b8893b1c5c
2
external/solanaceae_plugin
vendored
2
external/solanaceae_plugin
vendored
Submodule external/solanaceae_plugin updated: 17ffaee013...82cfb6d492
2
external/solanaceae_tox
vendored
2
external/solanaceae_tox
vendored
Submodule external/solanaceae_tox updated: b2a3cb7052...eeb57e137d
2
external/solanaceae_util
vendored
2
external/solanaceae_util
vendored
Submodule external/solanaceae_util updated: 390b123fb7...d304d719e9
BIN
res/tomato_screenshot_group_bot_text_23-02-2024.png
Normal file
BIN
res/tomato_screenshot_group_bot_text_23-02-2024.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
@ -37,7 +37,7 @@ namespace Components {
|
||||
|
||||
} // Components
|
||||
|
||||
static float lerp(float a, float b, float t) {
|
||||
static constexpr float lerp(float a, float b, float t) {
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
@ -121,8 +121,10 @@ ChatGui4::ChatGui4(
|
||||
ConfigModelI& conf,
|
||||
RegistryMessageModel& rmm,
|
||||
Contact3Registry& cr,
|
||||
TextureUploaderI& tu
|
||||
) : _conf(conf), _rmm(rmm), _cr(cr), _tal(_cr), _contact_tc(_tal, tu), _msg_tc(_mil, tu), _sip(tu) {
|
||||
TextureUploaderI& tu,
|
||||
ContactTextureCache& contact_tc,
|
||||
MessageTextureCache& msg_tc
|
||||
) : _conf(conf), _rmm(rmm), _cr(cr), _contact_tc(contact_tc), _msg_tc(msg_tc), _sip(tu) {
|
||||
}
|
||||
|
||||
ChatGui4::~ChatGui4(void) {
|
||||
@ -136,20 +138,7 @@ ChatGui4::~ChatGui4(void) {
|
||||
//}
|
||||
}
|
||||
|
||||
void ChatGui4::render(float time_delta) {
|
||||
if (!_cr.storage<Contact::Components::TagAvatarInvalidate>().empty()) { // handle force-reloads for avatars
|
||||
std::vector<Contact3> to_purge;
|
||||
_cr.view<Contact::Components::TagAvatarInvalidate>().each([&to_purge](const Contact3 c) {
|
||||
to_purge.push_back(c);
|
||||
});
|
||||
_cr.remove<Contact::Components::TagAvatarInvalidate>(to_purge.cbegin(), to_purge.cend());
|
||||
_contact_tc.invalidate(to_purge);
|
||||
}
|
||||
// ACTUALLY NOT IF RENDERED, MOVED LOGIC TO ABOVE
|
||||
// it might unload textures, so it needs to be done before rendering
|
||||
_contact_tc.update();
|
||||
_msg_tc.update();
|
||||
|
||||
float ChatGui4::render(float time_delta) {
|
||||
_fss.render();
|
||||
_sip.render(time_delta);
|
||||
|
||||
@ -335,6 +324,7 @@ void ChatGui4::render(float time_delta) {
|
||||
//tmp_view.use<Message::Components::Timestamp>();
|
||||
//tmp_view.each([&](const Message3 e, Message::Components::ContactFrom& c_from, Message::Components::ContactTo& c_to, Message::Components::Timestamp ts
|
||||
//) {
|
||||
uint64_t prev_ts {0};
|
||||
auto tmp_view = msg_reg.view<Message::Components::Timestamp>();
|
||||
for (auto view_it = tmp_view.rbegin(), view_last = tmp_view.rend(); view_it != view_last; view_it++) {
|
||||
const Message3 e = *view_it;
|
||||
@ -352,6 +342,34 @@ void ChatGui4::render(float time_delta) {
|
||||
// TODO: why?
|
||||
ImGui::TableNextRow(0, TEXT_BASE_HEIGHT);
|
||||
|
||||
{ // check if date changed
|
||||
// TODO: find defined ways of casting to time_t
|
||||
std::time_t prev = prev_ts / 1000;
|
||||
std::time_t next = ts.ts / 1000;
|
||||
std::tm prev_tm = *std::localtime(&prev);
|
||||
std::tm next_tm = *std::localtime(&next);
|
||||
if (
|
||||
prev_tm.tm_yday != next_tm.tm_yday ||
|
||||
prev_tm.tm_year != next_tm.tm_year // making sure
|
||||
) {
|
||||
// name
|
||||
if (ImGui::TableNextColumn()) {
|
||||
//ImGui::TextDisabled("---");
|
||||
}
|
||||
// msg
|
||||
if (ImGui::TableNextColumn()) {
|
||||
ImGui::TextDisabled("DATE CHANGED from %d.%d.%d to %d.%d.%d",
|
||||
1900+prev_tm.tm_year, 1+prev_tm.tm_mon, prev_tm.tm_mday,
|
||||
1900+next_tm.tm_year, 1+next_tm.tm_mon, next_tm.tm_mday
|
||||
);
|
||||
}
|
||||
ImGui::TableNextRow(0, TEXT_BASE_HEIGHT);
|
||||
}
|
||||
|
||||
prev_ts = ts.ts;
|
||||
}
|
||||
|
||||
|
||||
ImGui::PushID(entt::to_integral(e));
|
||||
|
||||
// name
|
||||
@ -627,8 +645,7 @@ void ChatGui4::render(float time_delta) {
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
_contact_tc.workLoadQueue();
|
||||
_msg_tc.workLoadQueue();
|
||||
return 1000.f; // TODO: higher min fps?
|
||||
}
|
||||
|
||||
void ChatGui4::sendFilePath(const char* file_path) {
|
||||
@ -749,7 +766,11 @@ void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
|
||||
) {
|
||||
if (ImGui::Button("save to")) {
|
||||
_fss.requestFile(
|
||||
[](const auto& path) -> bool { return std::filesystem::is_directory(path); },
|
||||
[](std::filesystem::path& path) -> bool {
|
||||
// remove file path
|
||||
path.remove_filename();
|
||||
return std::filesystem::is_directory(path);
|
||||
},
|
||||
[this, ®, e](const auto& path) {
|
||||
if (reg.valid(e)) { // still valid
|
||||
// TODO: trim file?
|
||||
|
@ -9,7 +9,8 @@
|
||||
#include "./message_image_loader.hpp"
|
||||
#include "./file_selector.hpp"
|
||||
#include "./send_image_popup.hpp"
|
||||
#include "entt/container/dense_map.hpp"
|
||||
|
||||
#include <entt/container/dense_map.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
@ -17,15 +18,16 @@
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
using ContactTextureCache = TextureCache<void*, Contact3, ToxAvatarLoader>;
|
||||
using MessageTextureCache = TextureCache<void*, Message3Handle, MessageImageLoader>;
|
||||
|
||||
class ChatGui4 {
|
||||
ConfigModelI& _conf;
|
||||
RegistryMessageModel& _rmm;
|
||||
Contact3Registry& _cr;
|
||||
|
||||
ToxAvatarLoader _tal;
|
||||
TextureCache<void*, Contact3, ToxAvatarLoader> _contact_tc;
|
||||
MessageImageLoader _mil;
|
||||
TextureCache<void*, Message3Handle, MessageImageLoader> _msg_tc;
|
||||
ContactTextureCache& _contact_tc;
|
||||
MessageTextureCache& _msg_tc;
|
||||
|
||||
FileSelector _fss;
|
||||
SendImagePopup _sip;
|
||||
@ -52,12 +54,14 @@ class ChatGui4 {
|
||||
ConfigModelI& conf,
|
||||
RegistryMessageModel& rmm,
|
||||
Contact3Registry& cr,
|
||||
TextureUploaderI& tu
|
||||
TextureUploaderI& tu,
|
||||
ContactTextureCache& contact_tc,
|
||||
MessageTextureCache& msg_tc
|
||||
);
|
||||
~ChatGui4(void);
|
||||
|
||||
public:
|
||||
void render(float time_delta);
|
||||
float render(float time_delta);
|
||||
|
||||
public:
|
||||
bool any_unread {false};
|
||||
|
@ -18,7 +18,7 @@ FileSelector::FileSelector(void) {
|
||||
}
|
||||
|
||||
void FileSelector::requestFile(
|
||||
std::function<bool(const std::filesystem::path& path)>&& is_valid,
|
||||
std::function<bool(std::filesystem::path& path)>&& is_valid,
|
||||
std::function<void(const std::filesystem::path& path)>&& on_choose,
|
||||
std::function<void(void)>&& on_cancel
|
||||
) {
|
||||
@ -77,7 +77,9 @@ void FileSelector::render(void) {
|
||||
if (current_path.has_parent_path()) {
|
||||
if (ImGui::TableNextColumn()) {
|
||||
if (ImGui::Selectable("D##..", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
_current_file_path = _current_file_path.parent_path();
|
||||
// the first "parent_path()" only removes the filename and the ending "/"
|
||||
_current_file_path = _current_file_path.parent_path().parent_path() / "";
|
||||
//_current_file_path = _current_file_path.remove_filename().parent_path() / "";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ struct FileSelector {
|
||||
|
||||
bool _open_popup {false};
|
||||
|
||||
std::function<bool(const std::filesystem::path& path)> _is_valid = [](auto){ return true; };
|
||||
std::function<bool(std::filesystem::path& path)> _is_valid = [](auto){ return true; };
|
||||
std::function<void(const std::filesystem::path& path)> _on_choose = [](auto){};
|
||||
std::function<void(void)> _on_cancel = [](){};
|
||||
|
||||
@ -18,8 +18,9 @@ struct FileSelector {
|
||||
FileSelector(void);
|
||||
|
||||
// TODO: supply hints
|
||||
// HACK: until we supply hints, is_valid can modify
|
||||
void requestFile(
|
||||
std::function<bool(const std::filesystem::path& path)>&& is_valid,
|
||||
std::function<bool(std::filesystem::path& path)>&& is_valid,
|
||||
std::function<void(const std::filesystem::path& path)>&& on_choose,
|
||||
std::function<void(void)>&& on_cancel
|
||||
);
|
||||
|
72
src/fragment_store/README.md
Normal file
72
src/fragment_store/README.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Fragment Store
|
||||
|
||||
Fragments are are pieces of information split into Metadata and Data.
|
||||
They can be stored seperated or together.
|
||||
They can be used as a Transport protocol/logic too.
|
||||
|
||||
# Store types
|
||||
|
||||
### Object Store
|
||||
|
||||
Fragment files are stored with the first 2 hex chars as sub folders:
|
||||
eg:
|
||||
`objects/` (object store root)
|
||||
- `5f/` (first 2hex subfolder)
|
||||
- `4fffffff` (the fragment file without the first 2 hexchars)
|
||||
|
||||
### Split Object Store
|
||||
|
||||
Same as Object Store, but medadata and data stored in seperate files.
|
||||
Metadata files have the `.meta` suffix. They also have a filetype specific suffix, like `.json`, `.msgpack` etc.
|
||||
|
||||
### Memory Store
|
||||
|
||||
Just keeps the Fragments in memory.
|
||||
|
||||
# File formats
|
||||
|
||||
Files can be compressed and encrypted. Since compression needs the data structure to funcion, it is applied before it is encrypted.
|
||||
|
||||
### Text Json
|
||||
|
||||
Text json only makes sense for metadata if it's neither compressed nor encrypted. (otherwise its binary on disk anyway, so why waste bytes).
|
||||
Since the content of data is not looked at, nothing stops you from using text json and ecrypt it, but atleast basic compression is advised.
|
||||
|
||||
A Metadata json object has the following keys:
|
||||
- `enc` (uint) Encryption type of the data, if any
|
||||
- `comp` (uint) Compression type of the data, if any
|
||||
- `metadata` (obj) the
|
||||
|
||||
## Binary file headers
|
||||
|
||||
### Split Metadata
|
||||
|
||||
file magic bytes `SOLMET` (6 bytes)
|
||||
|
||||
1 byte encryption type (`0x00` is none)
|
||||
|
||||
1 byte compression type (`0x00` is none)
|
||||
|
||||
...metadata here...
|
||||
|
||||
note that the encryption and compression are for the metadata only.
|
||||
The metadata itself contains encryption and compression info about the data.
|
||||
|
||||
### Split Data
|
||||
|
||||
(none) all the data is in the metadata file.
|
||||
This is mostly to allow direct storage for files in the Fragment store without excessive duplication.
|
||||
Keep in mind to not use the actual file name as the data/meta file name.
|
||||
|
||||
### Single fragment
|
||||
|
||||
file magic bytes `SOLFIL` (6 bytes)
|
||||
|
||||
1 byte encryption type (`0x00` is none)
|
||||
|
||||
1 byte compression type (`0x00` is none)
|
||||
|
||||
...metadata here...
|
||||
|
||||
...data here...
|
||||
|
10
src/main.cpp
10
src/main.cpp
@ -178,9 +178,13 @@ int main(int argc, char** argv) {
|
||||
//)
|
||||
//));
|
||||
|
||||
const float min_delay = std::min<float>(
|
||||
screen->nextTick() - time_delta_tick,
|
||||
screen->nextRender() - time_delta_render
|
||||
const float min_delay =
|
||||
std::min<float>(
|
||||
std::min<float>(
|
||||
screen->nextTick() - time_delta_tick,
|
||||
screen->nextRender() - time_delta_render
|
||||
),
|
||||
0.25f // dont sleep too long
|
||||
) * 1000.f;
|
||||
|
||||
if (min_delay > 0.f) {
|
||||
|
@ -1,10 +1,13 @@
|
||||
#include "./main_screen.hpp"
|
||||
|
||||
#include <solanaceae/contact/components.hpp>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
|
||||
MainScreen::MainScreen(SDL_Renderer* renderer_, std::string save_path, std::string save_password, std::vector<std::string> plugins) :
|
||||
renderer(renderer_),
|
||||
@ -20,7 +23,11 @@ MainScreen::MainScreen(SDL_Renderer* renderer_, std::string save_path, std::stri
|
||||
mmil(rmm),
|
||||
tam(rmm, cr, conf),
|
||||
sdlrtu(renderer_),
|
||||
cg(conf, rmm, cr, sdlrtu),
|
||||
tal(cr),
|
||||
contact_tc(tal, sdlrtu),
|
||||
mil(),
|
||||
msg_tc(mil, sdlrtu),
|
||||
cg(conf, rmm, cr, sdlrtu, contact_tc, msg_tc),
|
||||
sw(conf),
|
||||
tuiu(tc, conf),
|
||||
tdch(tpi)
|
||||
@ -167,7 +174,22 @@ Screen* MainScreen::render(float time_delta, bool&) {
|
||||
|
||||
const float pm_interval = pm.render(time_delta); // render
|
||||
|
||||
cg.render(time_delta); // render
|
||||
// TODO: move this somewhere else!!!
|
||||
// needs both tal and tc <.<
|
||||
if (!cr.storage<Contact::Components::TagAvatarInvalidate>().empty()) { // handle force-reloads for avatars
|
||||
std::vector<Contact3> to_purge;
|
||||
cr.view<Contact::Components::TagAvatarInvalidate>().each([&to_purge](const Contact3 c) {
|
||||
to_purge.push_back(c);
|
||||
});
|
||||
cr.remove<Contact::Components::TagAvatarInvalidate>(to_purge.cbegin(), to_purge.cend());
|
||||
contact_tc.invalidate(to_purge);
|
||||
}
|
||||
// ACTUALLY NOT IF RENDERED, MOVED LOGIC TO ABOVE
|
||||
// it might unload textures, so it needs to be done before rendering
|
||||
const float ctc_interval = contact_tc.update();
|
||||
const float msgtc_interval = msg_tc.update();
|
||||
|
||||
const float cg_interval = cg.render(time_delta); // render
|
||||
sw.render(); // render
|
||||
tuiu.render(); // render
|
||||
tdch.render(); // render
|
||||
@ -216,20 +238,136 @@ Screen* MainScreen::render(float time_delta, bool&) {
|
||||
ImGui::ShowDemoWindow();
|
||||
}
|
||||
|
||||
if (
|
||||
_fps_perf_mode > 1 // TODO: magic
|
||||
) {
|
||||
// powersave forces 250ms
|
||||
_render_interval = 1.f/4.f;
|
||||
} else if (
|
||||
_time_since_event > 1.f && ( // 1sec cool down
|
||||
_fps_perf_mode == 1 || // TODO: magic
|
||||
_window_hidden
|
||||
float tc_unfinished_queue_interval;
|
||||
{ // load rendered but not loaded textures
|
||||
bool unfinished_work_queue = contact_tc.workLoadQueue();
|
||||
unfinished_work_queue = unfinished_work_queue || msg_tc.workLoadQueue();
|
||||
|
||||
if (unfinished_work_queue) {
|
||||
tc_unfinished_queue_interval = 0.1f; // so we can get images loaded faster
|
||||
} else {
|
||||
tc_unfinished_queue_interval = 1.f; // TODO: higher min fps?
|
||||
}
|
||||
}
|
||||
|
||||
// calculate interval for next frame
|
||||
// normal:
|
||||
// - if < 1.5sec since last event
|
||||
// - min all and clamp(1/60, 1/1)
|
||||
// - if < 30sec since last event
|
||||
// - min all (anim + everything else) clamp(1/60, 1/1) (maybe less?)
|
||||
// - else
|
||||
// - min without anim and clamp(1/60, 1/1) (maybe more?)
|
||||
// reduced:
|
||||
// - if < 1sec since last event
|
||||
// - min all and clamp(1/60, 1/1)
|
||||
// - if < 10sec since last event
|
||||
// - min all (anim + everything else) clamp(1/10, 1/1)
|
||||
// - else
|
||||
// - min without anim and max clamp(1/10, 1/1)
|
||||
// powersave:
|
||||
// - if < 0sec since last event
|
||||
// - (ignored)
|
||||
// - if < 1sec since last event
|
||||
// - min all (anim + everything else) clamp(1/8, 1/1)
|
||||
// - else
|
||||
// - min without anim and clamp(1/1, 1/1)
|
||||
struct PerfProfileRender {
|
||||
float low_delay_window {1.5f};
|
||||
float low_delay_min {1.f/60.f};
|
||||
float low_delay_max {1.f/60.f};
|
||||
|
||||
float mid_delay_window {30.f};
|
||||
float mid_delay_min {1.f/60.f};
|
||||
float mid_delay_max {1.f/2.f};
|
||||
|
||||
// also when main window hidden
|
||||
float else_delay_min {1.f/60.f};
|
||||
float else_delay_max {1.f/2.f};
|
||||
};
|
||||
|
||||
const static PerfProfileRender normalPerfProfile{
|
||||
//1.5f, // low_delay_window
|
||||
//1.f/60.f, // low_delay_min
|
||||
//1.f/60.f, // low_delay_max
|
||||
|
||||
//30.f, // mid_delay_window
|
||||
//1.f/60.f, // mid_delay_min
|
||||
//1.f/2.f, // mid_delay_max
|
||||
|
||||
//1.f/60.f, // else_delay_min
|
||||
//1.f/2.f, // else_delay_max
|
||||
};
|
||||
const static PerfProfileRender reducedPerfProfile{
|
||||
1.f, // low_delay_window
|
||||
1.f/60.f, // low_delay_min
|
||||
1.f/30.f, // low_delay_max
|
||||
|
||||
10.f, // mid_delay_window
|
||||
1.f/10.f, // mid_delay_min
|
||||
1.f/4.f, // mid_delay_max
|
||||
|
||||
1.f/10.f, // else_delay_min
|
||||
1.f, // else_delay_max
|
||||
};
|
||||
// TODO: fix powersave by adjusting it in the events handler (make ppr member)
|
||||
const static PerfProfileRender powersavePerfProfile{
|
||||
// no window -> ignore first case
|
||||
0.f, // low_delay_window
|
||||
1.f, // low_delay_min
|
||||
1.f, // low_delay_max
|
||||
|
||||
1.f, // mid_delay_window
|
||||
1.f/8.f, // mid_delay_min
|
||||
1.f/4.f, // mid_delay_max
|
||||
|
||||
1.f, // else_delay_min
|
||||
1.f, // else_delay_max
|
||||
};
|
||||
|
||||
const PerfProfileRender& curr_profile =
|
||||
// TODO: magic
|
||||
_fps_perf_mode > 1
|
||||
? powersavePerfProfile
|
||||
: (
|
||||
_fps_perf_mode == 1
|
||||
? reducedPerfProfile
|
||||
: normalPerfProfile
|
||||
)
|
||||
) {
|
||||
_render_interval = std::min<float>(1.f/4.f, pm_interval);
|
||||
;
|
||||
|
||||
// min over non animations in all cases
|
||||
_render_interval = std::min<float>(pm_interval, cg_interval);
|
||||
_render_interval = std::min<float>(_render_interval, tc_unfinished_queue_interval);
|
||||
|
||||
// low delay time window
|
||||
if (!_window_hidden && _time_since_event < curr_profile.low_delay_window) {
|
||||
_render_interval = std::min<float>(_render_interval, ctc_interval);
|
||||
_render_interval = std::min<float>(_render_interval, msgtc_interval);
|
||||
|
||||
_render_interval = std::clamp(
|
||||
_render_interval,
|
||||
curr_profile.low_delay_min,
|
||||
curr_profile.low_delay_max
|
||||
);
|
||||
// mid delay time window
|
||||
} else if (!_window_hidden && _time_since_event < curr_profile.mid_delay_window) {
|
||||
_render_interval = std::min<float>(_render_interval, ctc_interval);
|
||||
_render_interval = std::min<float>(_render_interval, msgtc_interval);
|
||||
|
||||
_render_interval = std::clamp(
|
||||
_render_interval,
|
||||
curr_profile.mid_delay_min,
|
||||
curr_profile.mid_delay_max
|
||||
);
|
||||
// timed out or window hidden
|
||||
} else {
|
||||
_render_interval = std::min<float>(1.f/60.f, pm_interval);
|
||||
// no animation timing here
|
||||
_render_interval = std::clamp(
|
||||
_render_interval,
|
||||
curr_profile.else_delay_min,
|
||||
curr_profile.else_delay_max
|
||||
);
|
||||
}
|
||||
|
||||
_time_since_event += time_delta;
|
||||
@ -253,7 +391,9 @@ Screen* MainScreen::tick(float time_delta, bool& quit) {
|
||||
mts.iterate(); // compute
|
||||
|
||||
_min_tick_interval = std::min<float>(
|
||||
tc.toxIterationInterval()/1000.f,
|
||||
// HACK: pow by 1.6 to increase 50 -> ~500 (~522)
|
||||
// and it does not change 1
|
||||
std::pow(tc.toxIterationInterval(), 1.6f)/1000.f,
|
||||
pm_interval
|
||||
);
|
||||
_min_tick_interval = std::min<float>(
|
||||
@ -261,6 +401,8 @@ Screen* MainScreen::tick(float time_delta, bool& quit) {
|
||||
fo_interval
|
||||
);
|
||||
|
||||
//std::cout << "MS: min tick interval: " << _min_tick_interval << "\n";
|
||||
|
||||
switch (_compute_perf_mode) {
|
||||
// normal 1ms lower bound
|
||||
case 0: _min_tick_interval = std::max<float>(_min_tick_interval, 0.001f); break;
|
||||
|
@ -21,6 +21,10 @@
|
||||
#include "./tox_avatar_manager.hpp"
|
||||
|
||||
#include "./sdlrenderer_texture_uploader.hpp"
|
||||
#include "./texture_cache.hpp"
|
||||
#include "./tox_avatar_loader.hpp"
|
||||
#include "./message_image_loader.hpp"
|
||||
|
||||
#include "./chat_gui4.hpp"
|
||||
#include "./settings_window.hpp"
|
||||
#include "./tox_ui_utils.hpp"
|
||||
@ -61,6 +65,11 @@ struct MainScreen final : public Screen {
|
||||
SDLRendererTextureUploader sdlrtu;
|
||||
//OpenGLTextureUploader ogltu;
|
||||
|
||||
ToxAvatarLoader tal;
|
||||
TextureCache<void*, Contact3, ToxAvatarLoader> contact_tc;
|
||||
MessageImageLoader mil;
|
||||
TextureCache<void*, Message3Handle, MessageImageLoader> msg_tc;
|
||||
|
||||
ChatGui4 cg;
|
||||
SettingsWindow sw;
|
||||
ToxUIUtils tuiu;
|
||||
@ -85,7 +94,7 @@ struct MainScreen final : public Screen {
|
||||
// 0 - normal
|
||||
// 1 - reduced
|
||||
// 2 - power save
|
||||
int _fps_perf_mode {1};
|
||||
int _fps_perf_mode {0};
|
||||
// 0 - normal
|
||||
// 1 - power save
|
||||
int _compute_perf_mode {0};
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
|
||||
void TextureEntry::doAnimation(const int64_t ts_now) {
|
||||
int64_t TextureEntry::doAnimation(const int64_t ts_now) {
|
||||
if (frame_duration.size() > 1) { // is animation
|
||||
do { // why is this loop so ugly
|
||||
const int64_t duration = getDuration();
|
||||
@ -11,11 +12,13 @@ void TextureEntry::doAnimation(const int64_t ts_now) {
|
||||
timestamp_last_rendered += duration;
|
||||
next();
|
||||
} else {
|
||||
break;
|
||||
// return ts for next frame
|
||||
return timestamp_last_rendered + duration;
|
||||
}
|
||||
} while(true);
|
||||
} while (true);
|
||||
} else {
|
||||
timestamp_last_rendered = ts_now;
|
||||
return std::numeric_limits<int64_t>::max(); // static image
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,8 @@ struct TextureEntry {
|
||||
current_texture = (current_texture + 1) % frame_duration.size();
|
||||
}
|
||||
|
||||
void doAnimation(const int64_t ts_now);
|
||||
// returns ts for next frame
|
||||
int64_t doAnimation(const int64_t ts_now);
|
||||
|
||||
template<typename TextureType>
|
||||
TextureType getID(void) {
|
||||
@ -133,14 +134,16 @@ struct TextureCache {
|
||||
}
|
||||
}
|
||||
|
||||
void update(void) {
|
||||
float update(void) {
|
||||
const uint64_t ts_now = Message::getTimeMS();
|
||||
uint64_t ts_min_next = ts_now + ms_before_purge;
|
||||
|
||||
std::vector<KeyType> to_purge;
|
||||
for (auto&& [key, te] : _cache) {
|
||||
if (te.rendered_this_frame) {
|
||||
te.doAnimation(ts_now);
|
||||
const uint64_t ts_next = te.doAnimation(ts_now);
|
||||
te.rendered_this_frame = false;
|
||||
ts_min_next = std::min(ts_min_next, ts_next);
|
||||
} else if (_cache.size() > min_count_before_purge && ts_now - te.timestamp_last_rendered >= ms_before_purge) {
|
||||
to_purge.push_back(key);
|
||||
}
|
||||
@ -148,7 +151,10 @@ struct TextureCache {
|
||||
|
||||
invalidate(to_purge);
|
||||
|
||||
// we ignore the default texture ts :)
|
||||
_default_texture.doAnimation(ts_now);
|
||||
|
||||
return (ts_min_next - ts_now) / 1000.f;
|
||||
}
|
||||
|
||||
void invalidate(const std::vector<KeyType>& to_purge) {
|
||||
@ -162,16 +168,22 @@ struct TextureCache {
|
||||
}
|
||||
}
|
||||
|
||||
void workLoadQueue(void) {
|
||||
for (auto it = _to_load.begin(); it != _to_load.end(); it++) {
|
||||
// returns true if there is still work queued up
|
||||
bool workLoadQueue(void) {
|
||||
auto it = _to_load.begin();
|
||||
for (; it != _to_load.end(); it++) {
|
||||
auto new_entry_opt = _l.load(_tu, *it);
|
||||
if (new_entry_opt.has_value()) {
|
||||
_cache.emplace(*it, new_entry_opt.value());
|
||||
_to_load.erase(it);
|
||||
// TODO: not a good idea
|
||||
it = _to_load.erase(it);
|
||||
|
||||
// TODO: not a good idea?
|
||||
break; // end load from queue/onlyload 1 per update
|
||||
}
|
||||
}
|
||||
|
||||
// peak
|
||||
return it != _to_load.end();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -24,7 +24,7 @@ class ToxFriendFauxOfflineMessaging : public ToxEventI {
|
||||
|
||||
// TODO: increase timer?
|
||||
const float _delay_after_cc {4.5f};
|
||||
const float _delay_inbetween {1.3f};
|
||||
const float _delay_inbetween {0.3f};
|
||||
const float _delay_retry {10.f}; // retry sending after 10s
|
||||
|
||||
public:
|
||||
|
Reference in New Issue
Block a user