#include #include #include #include #include #include "app.hh" #include "input.hh" #define STB_IMAGE_IMPLEMENTATION #include namespace pg { namespace { class ImgSeq final : public App, public Input::Data { public: static inline TypeInfo kType = TypeInfo::Create("Input_ImgSeq"); ImgSeq() noexcept : Data("imgseq") { } ~ImgSeq() noexcept { DropCache(); } void DropCache() noexcept { for (auto& frame : frames_) { stbi_image_free(const_cast(frame.second.rgba)); } frames_.clear(); } void Update() noexcept override { const auto id = std::to_string(index())+" Input_ImgSeq | "+ std::to_string(reinterpret_cast(this)); if (ImGui::Begin(id.c_str())) { bool mod = false; mod |= ImGui::InputText("dir", &path_); mod |= ImGui::DragInt("start", &st_, 1, 0, 1024); mod |= ImGui::DragInt("end", &ed_, 1, 0, 1024); if (mod) DropCache(); if (msg_.size() > 0) { ImGui::TextUnformatted(msg_.c_str()); } } ImGui::End(); } Frame Fetch(size_t n) noexcept override try { n += static_cast(st_); if (n >= static_cast(ed_)) { throw "frame number out of range"; } auto itr = frames_.find(n); if (itr != frames_.end()) return itr->second; const auto fname = path_+"/"+std::to_string(n)+".png"; int w, h, comp; uint8_t* buf = stbi_load(fname.c_str(), &w, &h, &comp, 4); if (buf == nullptr) { throw stbi_failure_reason(); } const Frame ret = { .w = static_cast(w), .h = static_cast(h), .rgba = buf, }; frames_[n] = ret; return ret; } catch (const char* msg) { msg_ = msg; return {.w = 0, .h = 0, .rgba = nullptr}; } size_t frames() noexcept override { if (ed_ <= st_) return 0; return static_cast(ed_-st_); } private: std::string path_; int st_ = 1, ed_ = 100; std::string msg_; std::unordered_map frames_; }; } } // namespace pg