#include "app.hh" #include "input.hh" #include #include namespace pg { namespace { class Encoder final : public App, public Input::Data { public: static inline TypeInfo kType = TypeInfo::Create("Encoder"); Encoder() noexcept : Data("encoder") { } void Update() noexcept override { const auto id = std::to_string(index())+" Encoder | "+ std::to_string(reinterpret_cast(this)); if (ImGui::Begin(id.c_str())) { ImGui::DragInt("src", &src_, 1, 0, 1024); ImGui::DragInt("w", &w_, 1, 1, 1024); ImGui::DragInt("h", &h_, 1, 1, 1024); ImGui::DragInt2("block num", block_num_, 1, 1, 1024); ImGui::DragInt("utime", &utime_, 1, 5, 64); ImGui::InputTextMultiline("feats", &feats_); if (ImGui::Button("encode")) { Encode(); } } ImGui::End(); } Frame Fetch(size_t n) noexcept override { if (n >= frames_) return {}; const auto w = static_cast(w_); const auto h = static_cast(h_); return { .w = w, .h = h, .rgba = buf_.data()+4*w*h*n }; } size_t frames() noexcept override { return frames_; } private: int src_ = 0; int w_ = 128, h_ = 128; int block_num_[2] = {2, 2}; int utime_ = 10; std::string feats_; std::vector buf_; size_t frames_ = 0; struct Feat final { public: size_t block; char type; // C: const, L: linear }; void Encode() { const auto src = Input::instance().slots(static_cast(src_)); if (!src) throw "missing input"; const auto feats = ParseFeats(feats_); const auto w = static_cast(w_); const auto h = static_cast(h_); const auto utime = static_cast(utime_); buf_.resize(w*h*4*feats.size()*utime); frames_ = utime * feats.size(); const auto b_num_x = static_cast(block_num_[0]); const auto b_num_y = static_cast(block_num_[1]); const auto dst_bw = w/b_num_x; const auto dst_bh = h/b_num_y; std::vector> block_rgba(dst_bw*dst_bh*4); const auto dst_bw_f = static_cast(dst_bw); const auto dst_bh_f = static_cast(dst_bh); auto dst_ptr = buf_.data(); for (size_t t = 0; t < feats.size(); ++t) { const auto& f = feats[t]; const auto bx = f.block%b_num_x; const auto by = f.block/b_num_x; if (by < b_num_y) { { // get pixels in start of the feature const auto frame = src->Fetch(t*utime); if (!frame.rgba) throw "got an empty frame"; const auto bw = frame.w / b_num_x; const auto bh = frame.h / b_num_y; const auto bw_f = static_cast(bw); const auto bh_f = static_cast(bh); const auto off_x = bw*bx; const auto off_y = bh*by; auto itr = block_rgba.begin(); for (size_t y = 0; y < dst_bh; ++y) { const auto yf = static_cast(y) / dst_bh_f; for (size_t x = 0; x < dst_bw; ++x) { const auto xf = static_cast(x) / dst_bw_f; const auto srcx = static_cast(bw_f*xf) + off_x; const auto srcy = static_cast(bh_f*yf) + off_y; auto ptr = frame.rgba + 4*(frame.w*srcy+srcx); for (size_t i = 0; i < 4; ++i) { itr->first = *ptr; itr->second = *ptr; ++itr, ++ptr; } } } } if (f.type == 'L') { // get pixels in end frame if it's linear const auto frame = src->Fetch((t+1)*utime); if (!frame.rgba) throw "got an empty frame"; const auto bw = frame.w / b_num_x; const auto bh = frame.h / b_num_y; const auto bw_f = static_cast(bw); const auto bh_f = static_cast(bh); const auto off_x = bw*bx; const auto off_y = bh*by; auto itr = block_rgba.begin(); for (size_t y = 0; y < dst_bh; ++y) { const auto yf = static_cast(y) / dst_bh_f; for (size_t x = 0; x < dst_bw; ++x) { const auto xf = static_cast(x) / dst_bw_f; const auto srcx = static_cast(bw_f*xf) + off_x; const auto srcy = static_cast(bh_f*yf) + off_y; auto ptr = frame.rgba + 4*(frame.w*srcy+srcx); for (size_t i = 0; i < 4; ++i) { (itr++)->second = *(ptr++); } } } } } const auto bx_off = dst_bw*bx; const auto by_off = dst_bh*by; for (size_t bt = 0; bt < utime; ++bt) { const auto bt_f = static_cast(bt) / static_cast(utime); const auto frame = src->Fetch(t*utime+bt); if (!frame.rgba) throw "got an empty frame"; for (size_t y = 0; y < w; ++y) { for (size_t x = 0; x < h; ++x) { const bool is_target = bx_off <= x && x < bx_off+dst_bw && by_off <= y && y < by_off+dst_bh; if (is_target) { const auto* ptr = &block_rgba[4*((x-bx_off)+(y-by_off)*dst_bw)]; for (size_t i = 0; i < 4; ++i) { const auto a = static_cast(ptr->second-ptr->first); const auto b = static_cast(ptr->first); *(dst_ptr++) = static_cast(bt_f*a+b); ++ptr; } } else { const auto xf = static_cast(x) / static_cast(w); const auto yf = static_cast(y) / static_cast(h); const auto src_x = static_cast(static_cast(frame.w)*xf); const auto src_y = static_cast(static_cast(frame.h)*yf); auto ptr = frame.rgba + 4*(src_x+src_y*frame.w); for (size_t i = 0; i < 4; ++i) { *(dst_ptr++) = (*ptr++); } } } } } } } static std::vector ParseFeats(const std::string& script) { std::vector ret; const char* begin = &*script.c_str(); const char* end = begin + script.size(); size_t time = 0; for (auto itr = begin; itr < end; ++itr, ++time) { char* end; const auto idx = std::strtol(&*itr, &end, 0); if (itr == end) throw "invalid format: expected block index"; if (*end != 'C' && *end != 'L') { throw "invalid format: unknown type"; } itr = end+1; ret.push_back(Feat { .block = static_cast(idx), .type = *end, }); } return ret; } }; } } // namespace pg