Compare commits

...

8 Commits

Author SHA1 Message Date
bb510b685a fix some crashes (how) and bitset wierdness
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
2024-12-18 21:39:50 +01:00
876f482391 fix sdl image loder io leak and send image popup fixes
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
2024-12-18 21:12:20 +01:00
42dd6d16d7 fix reading char from empty line
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
2024-12-18 16:21:11 +01:00
11ae259f67 texture cache refactor to later allow async loading
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousDelivery / windows-asan (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
2024-12-16 00:32:07 +01:00
f2027befc8 fix bitset getting rendered all the time
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
2024-12-15 22:01:53 +01:00
9777cb81cb remote (combined) bitset have
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
2024-12-14 23:47:04 +01:00
84ade4d683 local have bitset rendering
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousDelivery / windows-asan (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
2024-12-13 00:53:48 +01:00
f89aeae62b indicate have all on ft
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
2024-12-12 15:36:16 +01:00
17 changed files with 396 additions and 82 deletions

View File

@ -56,6 +56,8 @@ target_sources(tomato PUBLIC
./tox_avatar_loader.cpp
./message_image_loader.hpp
./message_image_loader.cpp
./bitset_image_loader.hpp
./bitset_image_loader.cpp
./tox_avatar_manager.hpp
./tox_avatar_manager.cpp

153
src/bitset_image_loader.cpp Normal file
View File

@ -0,0 +1,153 @@
#include "./bitset_image_loader.hpp"
#include <solanaceae/object_store/object_store.hpp>
#include <solanaceae/object_store/meta_components_file.hpp>
#include "./os_comps.hpp"
#include <entt/entity/entity.hpp>
#include <SDL3/SDL.h>
#include <iostream>
// fwd
namespace Message {
uint64_t getTimeMS(void);
}
std::optional<TextureEntry> BitsetImageLoader::haveToTexture(TextureUploaderI& tu, BitSet& have, ObjectHandle o) {
assert(have.size_bits() > 0);
auto* surf = SDL_CreateSurfaceFrom(
have.size_bits(), 1,
SDL_PIXELFORMAT_INDEX1MSB, // LSB ?
have.data(), have.size_bytes()
);
if (surf == nullptr) {
std::cerr << "BIL error: bitset to 1bit surface creationg failed o:" << entt::to_integral(o.entity()) << "\n";
return std::nullopt;
}
SDL_Color colors[] {
{0, 0, 0, 0},
{255, 255, 255, 255},
};
SDL_Palette* palette = SDL_CreatePalette(2);
SDL_SetPaletteColors(palette, colors, 0, 2);
SDL_SetSurfacePalette(surf, palette);
auto* conv_surf = SDL_ConvertSurface(surf, SDL_PIXELFORMAT_RGBA32);
SDL_DestroySurface(surf);
SDL_DestroyPalette(palette);
if (conv_surf == nullptr) {
std::cerr << "BIL error: surface conversion failed o:" << entt::to_integral(o.entity()) << " : " << SDL_GetError() << "\n";
return std::nullopt;
}
SDL_LockSurface(conv_surf);
TextureEntry new_entry;
new_entry.timestamp_last_rendered = Message::getTimeMS();
new_entry.width = have.size_bits();
new_entry.height = 1;
const auto n_t = tu.upload(static_cast<uint8_t*>(conv_surf->pixels), conv_surf->w, conv_surf->h, TextureUploaderI::RGBA);
assert(n_t != 0);
new_entry.textures.push_back(n_t);
new_entry.frame_duration.push_back(1);
std::cout << "BIL: genereated bitset image o:" << entt::to_integral(o.entity()) << "\n";
SDL_UnlockSurface(conv_surf);
SDL_DestroySurface(conv_surf);
return new_entry;
}
BitsetImageLoader::BitsetImageLoader(void) {
}
TextureLoaderResult BitsetImageLoader::load(TextureUploaderI& tu, ObjectHandle o) {
if (!static_cast<bool>(o)) {
std::cerr << "BIL error: trying to load invalid object\n";
return {};
}
if (!o.any_of<ObjComp::F::LocalHaveBitset, ObjComp::F::RemoteHaveBitset>()) {
// after completion, this is called until the texture times out
//std::cout << "BIL: no have bitset\n";
return {};
}
if (o.all_of<ObjComp::F::LocalHaveBitset>()) {
auto& have = o.get<ObjComp::F::LocalHaveBitset>().have;
assert(have.size_bits() > 0);
return {haveToTexture(tu, have, o)};
} else if (o.all_of<ObjComp::F::RemoteHaveBitset>()) {
auto& list = o.get<ObjComp::F::RemoteHaveBitset>().others;
if (list.empty()) {
std::cout << "BIL: remote set list empty\n";
_tmp_bitset = {8};
return {haveToTexture(tu, _tmp_bitset, o)};
}
const auto& first_entry = list.begin()->second;
if (first_entry.have_all) {
_tmp_bitset = {8};
_tmp_bitset.invert();
std::cout << "BIL: remote first have all\n";
} else {
_tmp_bitset = first_entry.have;
assert(_tmp_bitset.size_bits() == first_entry.have.size_bits());
for (auto it = list.begin()+1; it != list.end(); it++) {
if (it->second.have_all) {
_tmp_bitset = {8};
_tmp_bitset.invert();
std::cout << "BIL: remote have all\n";
break;
}
_tmp_bitset.merge(it->second.have);
}
}
return {haveToTexture(tu, _tmp_bitset, o)};
}
return {};
}
std::optional<TextureEntry> BitsetImageLoader::load(TextureUploaderI& tu, ObjectContactSub ocs) {
if (!static_cast<bool>(ocs.o)) {
std::cerr << "BIL error: trying to load invalid object\n";
return std::nullopt;
}
if (!ocs.o.all_of<ObjComp::F::RemoteHaveBitset>()) {
// after completion, this is called until the texture times out
return std::nullopt;
}
auto& map = ocs.o.get<ObjComp::F::RemoteHaveBitset>().others;
auto it = map.find(ocs.c);
if (it == map.end()) {
// contact not found
return std::nullopt;
}
if (it->second.have_all) {
BitSet tmp{8}; // or 1?
tmp.invert();
return haveToTexture(tu, tmp, ocs.o);
} else if (it->second.have.size_bits() == 0) {
BitSet tmp{8}; // or 1?
return haveToTexture(tu, tmp, ocs.o);
} else {
return haveToTexture(tu, it->second.have, ocs.o);
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <solanaceae/object_store/fwd.hpp>
#include <solanaceae/contact/contact_model3.hpp>
#include <solanaceae/util/bitset.hpp>
#include "./texture_cache.hpp"
#include <optional>
struct ObjectContactSub final {
ObjectHandle o;
Contact3 c{entt::null};
};
template<>
struct std::hash<ObjectContactSub> {
std::size_t operator()(ObjectContactSub const& ocs) const noexcept {
const std::size_t h1 = reinterpret_cast<std::size_t>(ocs.o.registry());
const std::size_t h2 = entt::to_integral(ocs.o.entity());
const std::size_t h3 = entt::to_integral(ocs.c);
return (h1 << 3) ^ (h3 << 7) ^ (h2 * 11400714819323198485llu);
}
};
class BitsetImageLoader {
BitSet _tmp_bitset;
std::optional<TextureEntry> haveToTexture(TextureUploaderI& tu, BitSet& have, ObjectHandle o);
public:
BitsetImageLoader(void);
TextureLoaderResult load(TextureUploaderI& tu, ObjectHandle o);
std::optional<TextureEntry> load(TextureUploaderI& tu, ObjectContactSub ocs);
};

View File

@ -11,6 +11,8 @@
#include <imgui/imgui.h>
#include <cmath>
// fwd
namespace Message {
uint64_t getTimeMS(void);
@ -91,7 +93,7 @@ bool SendImagePopup::load(void) {
preview_image.timestamp_last_rendered = Message::getTimeMS();
preview_image.current_texture = 0;
for (const auto& [ms, data] : original_image.frames) {
const auto n_t = _tu.uploadRGBA(data.data(), original_image.width, original_image.height);
const auto n_t = _tu.upload(data.data(), original_image.width, original_image.height);
preview_image.textures.push_back(n_t);
preview_image.frame_duration.push_back(ms);
}

View File

@ -1,7 +1,5 @@
#include "./chat_gui4.hpp"
#include <solanaceae/object_store/object_store.hpp>
#include <solanaceae/message3/components.hpp>
#include <solanaceae/tox_messages/msg_components.hpp>
#include <solanaceae/tox_messages/obj_components.hpp>
@ -18,6 +16,7 @@
#include <imgui/imgui.h>
#include <imgui/misc/cpp/imgui_stdlib.h>
#include <imgui/imgui_internal.h>
#include <SDL3/SDL.h>
@ -25,6 +24,7 @@
#include "./media_meta_info_loader.hpp"
#include "./sdl_clipboard_utils.hpp"
#include "os_comps.hpp"
#include <cctype>
#include <ctime>
@ -246,7 +246,19 @@ ChatGui4::ChatGui4(
ContactTextureCache& contact_tc,
MessageTextureCache& msg_tc,
Theme& theme
) : _conf(conf), _os(os), _rmm(rmm), _cr(cr), _contact_tc(contact_tc), _msg_tc(msg_tc), _theme(theme), _sip(tu) {
) :
_conf(conf),
_os(os),
_os_sr(_os.newSubRef(this)),
_rmm(rmm),
_cr(cr),
_contact_tc(contact_tc),
_msg_tc(msg_tc),
_b_tc(_bil, tu),
_theme(theme),
_sip(tu)
{
_os_sr.subscribe(ObjectStore_Event::object_update);
}
ChatGui4::~ChatGui4(void) {
@ -263,6 +275,8 @@ ChatGui4::~ChatGui4(void) {
float ChatGui4::render(float time_delta) {
_fss.render();
_sip.render(time_delta);
_b_tc.update();
_b_tc.workLoadQueue();
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
@ -1030,7 +1044,7 @@ void ChatGui4::renderMessageBodyText(Message3Registry& reg, const Message3 e) {
ImGui::BeginGroup();
do {
const auto current_line = msgtext_sv.substr(pos_prev, pos_next - pos_prev);
if (current_line.front() == '>') {
if (!current_line.empty() && current_line.front() == '>') {
// TODO: theming
ImGui::PushStyleColor(ImGuiCol_Text, {0.3f, 0.9f, 0.1f, 1.f});
ImGui::TextUnformatted(current_line.data(), current_line.data()+current_line.size());
@ -1123,6 +1137,10 @@ void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
// TODO: missing other states
ImGui::TextUnformatted("running");
}
if (o.all_of<ObjComp::F::TagLocalHaveAll>()) {
ImGui::SameLine();
ImGui::TextUnformatted("(have all)");
}
// if in offered state
// paused, never started
@ -1158,6 +1176,8 @@ void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
// hacky
const auto* fts = o.try_get<ObjComp::Ephemeral::File::TransferStats>();
if (fts != nullptr && o.any_of<ObjComp::F::SingleInfo, ObjComp::F::CollectionInfo>()) {
const bool upload = o.all_of<ObjComp::F::TagLocalHaveAll>() && fts->total_down <= 0;
const int64_t total_size =
o.all_of<ObjComp::F::SingleInfo>() ?
o.get<ObjComp::F::SingleInfo>().file_size :
@ -1166,7 +1186,7 @@ void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
int64_t transfer_total {0u};
float transfer_rate {0.f};
if (o.all_of<ObjComp::F::TagLocalHaveAll>() && fts->total_down <= 0) {
if (upload) {
// if have all AND no dl -> show upload progress
ImGui::TextUnformatted(" up");
transfer_total = fts->total_up;
@ -1179,7 +1199,12 @@ void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
}
ImGui::SameLine();
float fraction = float(transfer_total) / total_size;
float fraction{0.f};
if (total_size > 0) {
fraction = float(transfer_total) / total_size;
} else if (o.all_of<ObjComp::F::TagLocalHaveAll>()) {
fraction = 1.f;
}
char overlay_buf[128];
if (transfer_rate > 0.000001f) {
@ -1207,11 +1232,57 @@ void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
std::snprintf(overlay_buf, sizeof(overlay_buf), "%.1f%%", fraction * 100 + 0.01f);
}
ImGui::ProgressBar(
fraction,
{-FLT_MIN, TEXT_BASE_HEIGHT},
overlay_buf
);
if (
(!upload && !o.all_of<ObjComp::F::TagLocalHaveAll>() && o.all_of<ObjComp::F::LocalHaveBitset>()) ||
(upload && o.all_of<ObjComp::F::RemoteHaveBitset>())
) {
ImGui::BeginGroup();
// TODO: hights are all off
ImGui::ProgressBar(
fraction,
{-FLT_MIN, TEXT_BASE_HEIGHT*0.66f},
overlay_buf
);
ImVec2 orig_curser_pos = ImGui::GetCursorPos();
const ImVec2 bar_size{ImGui::GetContentRegionAvail().x, TEXT_BASE_HEIGHT*0.15f};
// deploy dummy and check visibility
ImGui::Dummy(bar_size);
if (ImGui::IsItemVisible()) {
ImGui::SetCursorPos(orig_curser_pos); // reset before dummy
auto const cursor_start_vec = ImGui::GetCursorScreenPos();
// TODO: replace with own version, so we dont have to internal
ImGui::RenderFrame(
cursor_start_vec,
{
cursor_start_vec.x + bar_size.x,
cursor_start_vec.y + bar_size.y
},
ImGui::GetColorU32(ImGuiCol_FrameBg),
false
);
auto [id, img_width, img_height] = _b_tc.get(o);
ImGui::Image(
id,
bar_size,
{0.f, 0.f}, // default
{1.f, 1.f}, // default
ImGui::GetStyleColorVec4(ImGuiCol_PlotHistogram)
);
}
ImGui::EndGroup();
} else {
ImGui::ProgressBar(
fraction,
{-FLT_MIN, TEXT_BASE_HEIGHT},
overlay_buf
);
}
} else {
// infinite scrolling progressbar fallback
ImGui::TextUnformatted(" ??");
@ -1223,16 +1294,6 @@ void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
);
}
if (!o.all_of<ObjComp::F::TagLocalHaveAll>() && o.all_of<ObjComp::F::LocalHaveBitset>()) {
// texture based on have bitset
// TODO: missing have chunks/chunksize to get the correct size
//const auto& bitest = o.get<ObjComp::F::LocalHaveBitset>().have;
// generate 1bit sdlsurface zerocopy using bitset.data() and bitset.size_bytes()
// optionally scale down filtered (would copy)
// update texture? in cache?
}
if (o.all_of<ObjComp::F::FrameDims>()) {
const auto& frame_dims = o.get<ObjComp::F::FrameDims>();
@ -1717,3 +1778,11 @@ void ChatGui4::sendFileList(const std::vector<std::string_view>& list) {
}
}
bool ChatGui4::onEvent(const ObjectStore::Events::ObjectUpdate& e) {
if (e.e.any_of<ObjComp::F::LocalHaveBitset, ObjComp::F::RemoteHaveBitset>()) {
_b_tc.stale(e.e);
}
return false;
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <solanaceae/object_store/fwd.hpp>
#include <solanaceae/object_store/object_store.hpp>
#include <solanaceae/message3/registry_message_model.hpp>
#include <solanaceae/util/config_model.hpp>
@ -10,6 +10,7 @@
#include "./texture_cache.hpp"
#include "./tox_avatar_loader.hpp"
#include "./message_image_loader.hpp"
#include "./bitset_image_loader.hpp"
#include "./chat_gui/file_selector.hpp"
#include "./chat_gui/send_image_popup.hpp"
@ -23,15 +24,19 @@
using ContactTextureCache = TextureCache<void*, Contact3, ToxAvatarLoader>;
using MessageTextureCache = TextureCache<void*, Message3Handle, MessageImageLoader>;
using BitsetTextureCache = TextureCache<void*, ObjectHandle, BitsetImageLoader>;
class ChatGui4 {
class ChatGui4 : public ObjectStoreEventI {
ConfigModelI& _conf;
ObjectStore2& _os;
ObjectStoreEventProviderI::SubscriptionReference _os_sr;
RegistryMessageModelI& _rmm;
Contact3Registry& _cr;
ContactTextureCache& _contact_tc;
MessageTextureCache& _msg_tc;
BitsetImageLoader _bil;
BitsetTextureCache _b_tc;
Theme& _theme;
@ -86,6 +91,9 @@ class ChatGui4 {
//bool renderSubContactListContact(const Contact3 c, const bool selected) const;
void pasteFile(const char* mime_type);
protected:
bool onEvent(const ObjectStore::Events::ObjectUpdate&) override;
};

View File

@ -55,6 +55,7 @@ ImageLoaderSDLImage::ImageInfo ImageLoaderSDLImage::loadInfoFromMemory(const uin
// we ignore tga
auto ext_opt = getExt(ios);
if (!ext_opt.has_value()) {
SDL_CloseIO(ios);
return res;
}
@ -80,6 +81,7 @@ ImageLoaderSDLImage::ImageResult ImageLoaderSDLImage::loadFromMemoryRGBA(const u
// we ignore tga
auto ext_opt = getExt(ios);
if (!ext_opt.has_value()) {
SDL_CloseIO(ios);
return res;
}

View File

@ -30,29 +30,29 @@ MessageImageLoader::MessageImageLoader(void) {
_image_loaders.push_back(std::make_unique<ImageLoaderSDLImage>());
}
std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Message3Handle m) {
TextureLoaderResult MessageImageLoader::load(TextureUploaderI& tu, Message3Handle m) {
if (!static_cast<bool>(m)) {
return std::nullopt;
return {std::nullopt};
}
if (m.all_of<Message::Components::TagNotImage>()) {
return std::nullopt;
return {std::nullopt};
}
if (!m.all_of<Message::Components::MessageFileObject>()) {
// not a file message
return std::nullopt;
return {std::nullopt};
}
const auto& o = m.get<Message::Components::MessageFileObject>().o;
if (!static_cast<bool>(o)) {
std::cerr << "MIL error: invalid object in file message\n";
return std::nullopt;
return {std::nullopt};
}
if (!o.all_of<ObjComp::Ephemeral::Backend, ObjComp::F::SingleInfo>()) {
std::cerr << "MIL error: object missing backend (?)\n";
return std::nullopt;
return {std::nullopt};
}
// TODO: handle collections
@ -60,40 +60,40 @@ std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Messa
if (file_size > 50*1024*1024) {
std::cerr << "MIL error: image file too large\n";
return std::nullopt;
return {std::nullopt};
}
if (file_size == 0) {
std::cerr << "MIL warning: empty file\n";
return std::nullopt;
return {std::nullopt};
}
if (!o.all_of<ObjComp::F::TagLocalHaveAll>()) {
// not ready yet
return std::nullopt;
return {std::nullopt};
}
auto* file_backend = o.get<ObjComp::Ephemeral::Backend>().ptr;
if (file_backend == nullptr) {
std::cerr << "MIL error: object backend nullptr\n";
return std::nullopt;
return {std::nullopt};
}
auto file2 = file_backend->file2(o, StorageBackendI::FILE2_READ);
if (!file2 || !file2->isGood() || !file2->can_read) {
std::cerr << "MIL error: creating file2 from object via backendI\n";
return std::nullopt;
return {std::nullopt};
}
auto read_data = file2->read(file_size, 0);
if (read_data.ptr == nullptr) {
std::cerr << "MMIL error: reading from file2 returned nullptr\n";
return std::nullopt;
return {std::nullopt};
}
if (read_data.size != file_size) {
std::cerr << "MIL error: reading from file2 size missmatch, should be " << file_size << ", is " << read_data.size << "\n";
return std::nullopt;
return {std::nullopt};
}
// try all loaders after another
@ -107,7 +107,7 @@ std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Messa
new_entry.timestamp_last_rendered = Message::getTimeMS();
new_entry.current_texture = 0;
for (const auto& [ms, data] : res.frames) {
const auto n_t = tu.uploadRGBA(data.data(), res.width, res.height);
const auto n_t = tu.upload(data.data(), res.width, res.height);
new_entry.textures.push_back(n_t);
new_entry.frame_duration.push_back(ms);
}
@ -117,10 +117,10 @@ std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Messa
std::cout << "MIL: loaded image file o:" << /*file_path*/ entt::to_integral(o.entity()) << "\n";
return new_entry;
return {new_entry};
}
std::cerr << "MIL error: failed to load message (unhandled format)\n";
return std::nullopt;
return {std::nullopt};
}

View File

@ -12,6 +12,6 @@ class MessageImageLoader {
public:
MessageImageLoader(void);
std::optional<TextureEntry> load(TextureUploaderI& tu, Message3Handle c);
TextureLoaderResult load(TextureUploaderI& tu, Message3Handle m);
};

View File

@ -8,21 +8,6 @@
namespace ObjectStore::Components {
// until i find a better name
namespace File {
// ephemeral?, not sure saving this to disk makes sense
// tag remove have all?
struct RemoteHaveBitset {
struct Entry {
bool have_all {false};
BitSet have;
};
entt::dense_map<Contact3, Entry> others;
};
} // File
namespace Ephemeral {
namespace File {

View File

@ -18,8 +18,6 @@ constexpr std::string_view entt::type_name<x>::value() noexcept { \
// cross compile(r) stable ids
DEFINE_COMP_ID(ObjComp::F::RemoteHaveBitset)
DEFINE_COMP_ID(ObjComp::Ephemeral::File::TransferStatsSeparated)
#undef DEFINE_COMP_ID

View File

@ -46,7 +46,7 @@ TextureEntry generateTestAnim(TextureUploaderI& tu) {
}
}
const auto n_t = tu.uploadRGBA(pixels.data(), width, height);
const auto n_t = tu.upload(pixels.data(), width, height);
// this is so ugly
new_entry.textures.emplace_back(n_t);

View File

@ -5,6 +5,10 @@
#include <entt/container/dense_map.hpp>
#include <entt/container/dense_set.hpp>
#include <optional>
#include <vector>
#include <cassert>
#include <iostream>
struct TextureEntry {
@ -70,6 +74,11 @@ struct TextureEntry {
}
};
struct TextureLoaderResult {
std::optional<TextureEntry> texture;
bool keep_trying{false}; // if set, cant be cleared, as some async might be going on
};
TextureEntry generateTestAnim(TextureUploaderI& tu);
// fwd
@ -91,6 +100,7 @@ struct TextureCache {
entt::dense_map<KeyType, TextureEntry> _cache;
entt::dense_set<KeyType> _to_load;
// to_reload // to_update? _marked_stale?
const uint64_t ms_before_purge {60 * 1000ull};
const size_t min_count_before_purge {0}; // starts purging after that
@ -134,6 +144,18 @@ struct TextureCache {
}
}
// markes a texture as stale and will reload it
// only if it already is loaded, does not update ts
bool stale(const KeyType& key) {
auto it = _cache.find(key);
if (it == _cache.end()) {
return false;
}
_to_load.insert(key);
return true;
}
float update(void) {
const uint64_t ts_now = Message::getTimeMS();
uint64_t ts_min_next = ts_now + ms_before_purge;
@ -144,7 +166,10 @@ struct TextureCache {
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) {
} else if (
_cache.size() > min_count_before_purge &&
ts_now - te.timestamp_last_rendered >= ms_before_purge
) {
to_purge.push_back(key);
}
}
@ -159,31 +184,64 @@ struct TextureCache {
void invalidate(const std::vector<KeyType>& to_purge) {
for (const auto& key : to_purge) {
if (_to_load.count(key)) {
// TODO: only remove if not keep trying
_to_load.erase(key);
}
if (_cache.count(key)) {
for (const auto& tex_id : _cache.at(key).textures) {
_tu.destroy(tex_id);
}
_cache.erase(key);
}
_cache.erase(key);
}
}
// returns true if there is still work queued up
bool workLoadQueue(void) {
auto it = _to_load.begin();
for (; it != _to_load.end(); it++) {
auto it = _to_load.cbegin();
for (; it != _to_load.cend(); it++) {
auto new_entry_opt = _l.load(_tu, *it);
if (new_entry_opt.has_value()) {
_cache.emplace(*it, new_entry_opt.value());
it = _to_load.erase(it);
if (_cache.count(*it)) {
if (new_entry_opt.texture.has_value()) {
auto old_entry = _cache.at(*it); // copy
assert(!old_entry.textures.empty());
for (const auto& tex_id : old_entry.textures) {
_tu.destroy(tex_id);
}
// TODO: not a good idea?
break; // end load from queue/onlyload 1 per update
_cache.erase(*it);
auto& new_entry = _cache[*it] = new_entry_opt.texture.value();
// TODO: make update interface and let loader handle this
//new_entry.current_texture = old_entry.current_texture; // ??
new_entry.rendered_this_frame = old_entry.rendered_this_frame;
new_entry.timestamp_last_rendered = old_entry.timestamp_last_rendered;
it = _to_load.erase(it);
// TODO: not a good idea?
break; // end load from queue/onlyload 1 per update
} else if (!new_entry_opt.keep_trying) {
// failed to load and the loader is done
it = _to_load.erase(it);
}
} else {
if (new_entry_opt.texture.has_value()) {
_cache.emplace(*it, new_entry_opt.texture.value());
_cache.at(*it).rendered_this_frame = true; // ?
it = _to_load.erase(it);
// TODO: not a good idea?
break; // end load from queue/onlyload 1 per update
} else if (!new_entry_opt.keep_trying) {
// failed to load and the loader is done
it = _to_load.erase(it);
}
}
}
// peak
return it != _to_load.end();
// peek
return it != _to_load.cend();
}
};

View File

@ -4,6 +4,7 @@
#include "./image_loader_qoi.hpp"
#include "./image_loader_webp.hpp"
#include "./image_loader_sdl_image.hpp"
#include "texture_uploader.hpp"
#include <solanaceae/contact/components.hpp>
#include <solanaceae/tox_contacts/components.hpp>
@ -119,9 +120,9 @@ static std::vector<uint8_t> generateToxIdenticon(const ToxKey& key) {
return pixels;
}
std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 c) {
TextureLoaderResult ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 c) {
if (!_cr.valid(c)) {
return std::nullopt;
return {std::nullopt};
}
if (_cr.all_of<Contact::Components::AvatarMemory>(c)) {
@ -134,13 +135,13 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
new_entry.width = a_m.width;
new_entry.height = a_m.height;
const auto n_t = tu.uploadRGBA(a_m.data.data(), a_m.width, a_m.height);
const auto n_t = tu.upload(a_m.data.data(), a_m.width, a_m.height);
new_entry.textures.push_back(n_t);
new_entry.frame_duration.push_back(250);
std::cout << "TAL: loaded memory buffer\n";
return new_entry;
return {new_entry};
}
if (_cr.all_of<Contact::Components::AvatarFile>(c)) {
@ -169,7 +170,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
new_entry.timestamp_last_rendered = Message::getTimeMS();
new_entry.current_texture = 0;
for (const auto& [ms, data] : res.frames) {
const auto n_t = tu.uploadRGBA(data.data(), res.width, res.height);
const auto n_t = tu.upload(data.data(), res.width, res.height);
new_entry.textures.push_back(n_t);
new_entry.frame_duration.push_back(ms);
}
@ -179,7 +180,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
std::cout << "TAL: loaded image file " << a_f.file_path << "\n";
return new_entry;
return {new_entry};
}
}
} // continues if loading img fails
@ -190,7 +191,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
Contact::Components::ToxGroupPeerPersistent,
Contact::Components::ID
>(c)) {
return std::nullopt;
return {std::nullopt};
}
std::vector<uint8_t> pixels;
@ -212,7 +213,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
new_entry.timestamp_last_rendered = Message::getTimeMS();
new_entry.current_texture = 0;
const auto n_t = tu.uploadRGBA(pixels.data(), 5, 5, TextureUploaderI::NEAREST);
const auto n_t = tu.upload(pixels.data(), 5, 5, TextureUploaderI::RGBA, TextureUploaderI::NEAREST);
new_entry.textures.push_back(n_t);
new_entry.frame_duration.push_back(250);
@ -221,6 +222,6 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
std::cout << "TAL: generated ToxIdenticon\n";
return new_entry;
return {new_entry};
}

View File

@ -14,6 +14,6 @@ class ToxAvatarLoader {
public:
ToxAvatarLoader(Contact3Registry& cr);
std::optional<TextureEntry> load(TextureUploaderI& tu, Contact3 c);
TextureLoaderResult load(TextureUploaderI& tu, Contact3 c);
};