#pragma once #include "./texture_uploader.hpp" #include #include #include struct TextureEntry { uint32_t width {0}; uint32_t height {0}; std::vector textures; std::vector frame_duration; // ms size_t current_texture {0}; bool rendered_this_frame {false}; // or flipped for animations uint64_t timestamp_last_rendered {0}; // ms TextureEntry(void) = default; TextureEntry(const TextureEntry& other) : width(other.width), height(other.height), textures(other.textures), frame_duration(other.frame_duration), current_texture(other.current_texture), rendered_this_frame(other.rendered_this_frame), timestamp_last_rendered(other.timestamp_last_rendered) {} TextureEntry& operator=(const TextureEntry& other) { width = other.width; height = other.height; textures = other.textures; frame_duration = other.frame_duration; current_texture = other.current_texture; rendered_this_frame = other.rendered_this_frame; timestamp_last_rendered = other.timestamp_last_rendered; return *this; } uint32_t getDuration(void) const { return frame_duration.at(current_texture); } void next(void) { current_texture = (current_texture + 1) % frame_duration.size(); } void doAnimation(const uint64_t ts_now); template TextureType getID(void) { static_assert( sizeof(TextureType) == sizeof(uint64_t) || sizeof(TextureType) == sizeof(uint32_t) ); rendered_this_frame = true; assert(current_texture < textures.size()); if constexpr (sizeof(TextureType) == sizeof(uint64_t)) { return reinterpret_cast(textures.at(current_texture)); } else if constexpr (sizeof(TextureType) == sizeof(uint32_t)) { return reinterpret_cast(static_cast(textures.at(current_texture))); } } }; TextureEntry generateTestAnim(TextureUploaderI& tu); uint64_t getNowMS(void); template struct TextureCache { static_assert( sizeof(TextureType) == sizeof(uint64_t) || sizeof(TextureType) == sizeof(uint32_t) ); TextureUploaderI& _tu; TextureEntry _default_texture; entt::dense_map _cache; entt::dense_set _to_load; 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) { //_image_loaders.push_back(std::make_unique()); //_image_loaders.push_back(std::make_unique()); _default_texture = generateTestAnim(_tu); //_default_texture = loadTestWebPAnim(); } struct GetInfo { TextureType id; uint32_t width; uint32_t height; }; GetInfo get(const KeyType& key) { auto it = _cache.find(key); if (it != _cache.end()) { return { it->second.template getID(), it->second.width, it->second.height }; } else { _to_load.insert(key); return { _default_texture.getID(), _default_texture.width, _default_texture.height }; } } void update(void) { const uint64_t ts_now = getNowMS(); std::vector to_purge; for (auto&& [key, te] : _cache) { if (te.rendered_this_frame) { te.doAnimation(ts_now); te.rendered_this_frame = false; } else if (_cache.size() > min_count_before_purge && ts_now - te.timestamp_last_rendered >= ms_before_purge) { to_purge.push_back(key); } } for (const auto& key : to_purge) { for (const auto& tex_id : _cache.at(key).textures) { _tu.destroy(tex_id); } _cache.erase(key); } _default_texture.doAnimation(ts_now); } };