From 75f78f8c7f7a76fd722605a444442e09f8eb23e2 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Tue, 1 Aug 2023 13:21:16 +0200 Subject: [PATCH] load tox identicons --- src/CMakeLists.txt | 2 + src/chat_gui4.cpp | 4 +- src/chat_gui4.hpp | 4 +- src/texture_cache.hpp | 18 ++++- src/tox_avatar_loader.cpp | 140 ++++++++++++++++++++++++++++++++++++++ src/tox_avatar_loader.hpp | 16 +++++ 6 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 src/tox_avatar_loader.cpp create mode 100644 src/tox_avatar_loader.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cebafdb..5334745 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,8 @@ add_executable(tomato ./sdlrenderer_texture_uploader.cpp ./texture_cache.hpp ./texture_cache.cpp + ./tox_avatar_loader.hpp + ./tox_avatar_loader.cpp ./sdl_clipboard_utils.hpp ./sdl_clipboard_utils.cpp ./file_selector.hpp diff --git a/src/chat_gui4.cpp b/src/chat_gui4.cpp index 4d03bb2..b0dc638 100644 --- a/src/chat_gui4.cpp +++ b/src/chat_gui4.cpp @@ -27,7 +27,7 @@ ChatGui4::ChatGui4( RegistryMessageModel& rmm, Contact3Registry& cr, TextureUploaderI& tu -) : _conf(conf), _rmm(rmm), _cr(cr), _contact_tc(tu) { +) : _conf(conf), _rmm(rmm), _cr(cr), _tal(_cr), _contact_tc(_tal, tu) { } void ChatGui4::render(void) { @@ -277,7 +277,7 @@ void ChatGui4::render(void) { _fss.render(); _contact_tc.update(); - //_tc.workLoadQueue(); + _contact_tc.workLoadQueue(); } // has MessageText diff --git a/src/chat_gui4.hpp b/src/chat_gui4.hpp index dc6d09d..43e62b3 100644 --- a/src/chat_gui4.hpp +++ b/src/chat_gui4.hpp @@ -5,6 +5,7 @@ #include "./texture_uploader.hpp" #include "./texture_cache.hpp" +#include "./tox_avatar_loader.hpp" #include "./file_selector.hpp" #include @@ -15,7 +16,8 @@ class ChatGui4 { RegistryMessageModel& _rmm; Contact3Registry& _cr; - TextureCache _contact_tc; + ToxAvatarLoader _tal; + TextureCache _contact_tc; //TextureCache _msg_tc; FileSelector _fss; diff --git a/src/texture_cache.hpp b/src/texture_cache.hpp index f3021d6..cfcee68 100644 --- a/src/texture_cache.hpp +++ b/src/texture_cache.hpp @@ -71,15 +71,17 @@ struct TextureEntry { TextureEntry generateTestAnim(TextureUploaderI& tu); +// TODO: move to utils or something uint64_t getNowMS(void); -template +template struct TextureCache { static_assert( sizeof(TextureType) == sizeof(uint64_t) || sizeof(TextureType) == sizeof(uint32_t) ); + Loader& _l; TextureUploaderI& _tu; TextureEntry _default_texture; @@ -90,7 +92,7 @@ struct TextureCache { const uint64_t ms_before_purge {60 * 1000ull}; const size_t min_count_before_purge {0}; // starts purging after that - TextureCache(TextureUploaderI& tu) : _tu(tu) { + TextureCache(Loader& l, TextureUploaderI& tu) : _l(l), _tu(tu) { //_image_loaders.push_back(std::make_unique()); //_image_loaders.push_back(std::make_unique()); _default_texture = generateTestAnim(_tu); @@ -143,5 +145,17 @@ struct TextureCache { _default_texture.doAnimation(ts_now); } + + void workLoadQueue(void) { + for (auto it = _to_load.begin(); 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 + break; // end load from queue/onlyload 1 per update + } + } + } }; diff --git a/src/tox_avatar_loader.cpp b/src/tox_avatar_loader.cpp new file mode 100644 index 0000000..ab6e129 --- /dev/null +++ b/src/tox_avatar_loader.cpp @@ -0,0 +1,140 @@ +#include "./tox_avatar_loader.hpp" + +#include + +#include + +#include +#include +#include + +static float getHue_6bytes(const uint8_t* data) { + uint64_t hue_uint = 0x00; + for (size_t i = 0; i < 6; i++) { + hue_uint = hue_uint << 8; + hue_uint += data[i]; + } + + // 48bit max (6bytes) + return float(hue_uint / 281474976710655.); +} + +static float hue2Rgb(float p, float q, float t) { + while (t < 0.f) { t += 1.f; } + while (t > 1.f) { t -= 1.f; } + if (t < 1.f/6.f) { return p + (q - p) * 6.f * t; } + if (t < 1.f/2.f) { return q; } + if (t < 2.f/3.f) { return p + (q - p) * (4.f - 6.f * t); } + return p; +} + +//https://github.com/Tox/Tox-Client-Standard/blob/master/appendix/ToxIdenticons.md +// creates a 5x5 pix texture RGBA8888 +static std::vector generateToxIdenticon(const ToxKey& key) { + // first hash key + std::array hashed_key; + assert(hashed_key.size() == key.data.size()); + crypto_hash_sha256(hashed_key.data(), key.data.data(), key.data.size()); + + const float hue_color1 = getHue_6bytes(hashed_key.data()+26); + const float hue_color2 = getHue_6bytes(hashed_key.data()+20); + + const float sat_color1 = 0.5f; + const float lig_color1 = 0.3f; + + const float sat_color2 = 0.5f; + const float lig_color2 = 0.8f; + + // TODO: refactor this mess + +#define Q(LIG, SAT) (LIG) < 0.5f ? (LIG) * (1 + (SAT)) : (LIG) + (SAT) - (LIG) * (SAT) + const float q_color1 = Q(lig_color1, sat_color1); + const float q_color2 = Q(lig_color2, sat_color2); +#undef Q + +#define P(LIG, Q) 2.f * (LIG) - (Q) + const float p_color1 = P(lig_color1, q_color1); + const float p_color2 = P(lig_color2, q_color2); +#undef P + + const uint8_t color_1_r = hue2Rgb(p_color1, q_color1, hue_color1 + 1.f/3.f) * 255.f + 0.499f; + const uint8_t color_1_g = hue2Rgb(p_color1, q_color1, hue_color1) * 255.f + 0.499f; + const uint8_t color_1_b = hue2Rgb(p_color1, q_color1, hue_color1 - 1.f/3.f) * 255.f + 0.499f; + + const uint8_t color_2_r = hue2Rgb(p_color2, q_color2, hue_color2 + 1.f/3.f) * 255.f + 0.499f; + const uint8_t color_2_g = hue2Rgb(p_color2, q_color2, hue_color2) * 255.f + 0.499f; + const uint8_t color_2_b = hue2Rgb(p_color2, q_color2, hue_color2 - 1.f/3.f) * 255.f + 0.499f; + + // start drawing + + std::vector pixels(5*5*4, 0xff); // fill with white +#define R(x,y) pixels[(y*4*5) + (4*x+0)] +#define G(x,y) pixels[(y*4*5) + (4*x+1)] +#define B(x,y) pixels[(y*4*5) + (4*x+2)] +#define COLOR1(x,y) R(x, y) = color_1_r; G(x, y) = color_1_g; B(x, y) = color_1_b; +#define COLOR2(x,y) R(x, y) = color_2_r; G(x, y) = color_2_g; B(x, y) = color_2_b; + + for (int64_t y = 0; y < 5; y++) { + for (int64_t x = 0; x < 5; x++) { + // mirrored index + //int64_t m_x = x <= 3 ? 3 : x - (x-2)*2; + int64_t m_x = ((x*2)-4)/2; + m_x = m_x < 0 ? -m_x : m_x; + + int64_t pos = y * 3 + m_x; + const uint8_t byte = hashed_key[pos]; + const uint8_t color = byte % 2; + if (color == 0) { + COLOR1(x, y) + } else { + COLOR2(x, y) + } + } + } + +#undef COLOR1 +#undef COLOR2 +#undef R +#undef G +#undef B + return pixels; +} + +std::optional ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 c) { + if (!_cr.valid(c)) { + return std::nullopt; + } + + if (!_cr.any_of< + Contact::Components::ToxFriendPersistent, + Contact::Components::ToxGroupPersistent, + Contact::Components::ToxGroupPeerPersistent + >(c)) { + return std::nullopt; + } + + std::vector pixels; + if (_cr.all_of(c)) { + pixels = generateToxIdenticon(_cr.get(c).key); + } else if (_cr.all_of(c)) { + pixels = generateToxIdenticon(_cr.get(c).chat_id); + } else if (_cr.all_of(c)) { + pixels = generateToxIdenticon(_cr.get(c).peer_key); + } + + TextureEntry new_entry; + new_entry.timestamp_last_rendered = getNowMS(); + new_entry.current_texture = 0; + + const auto n_t = tu.uploadRGBA(pixels.data(), 5, 5); + new_entry.textures.push_back(n_t); + new_entry.frame_duration.push_back(250); + + new_entry.width = 5; + new_entry.height = 5; + + std::cout << "TAL: generateToxIdenticon\n"; + + return new_entry; +} + diff --git a/src/tox_avatar_loader.hpp b/src/tox_avatar_loader.hpp new file mode 100644 index 0000000..08f91d8 --- /dev/null +++ b/src/tox_avatar_loader.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "./texture_cache.hpp" + +#include + +class ToxAvatarLoader { + Contact3Registry& _cr; + + public: + ToxAvatarLoader(Contact3Registry& cr) : _cr(cr) {} + std::optional load(TextureUploaderI& tu, Contact3 c); +}; +