blocky/playground/encoder.cc
2022-06-22 11:48:52 +09:00

212 lines
6.6 KiB
C++

#include "app.hh"
#include "input.hh"
#include <imgui.h>
#include <imgui_stdlib.h>
namespace pg {
namespace {
class Encoder final : public App, public Input::Data {
public:
static inline TypeInfo kType = TypeInfo::Create<Encoder>("Encoder");
Encoder() noexcept : Data("encoder") {
}
void Update() noexcept override {
const auto id = std::to_string(index())+" Encoder | "+
std::to_string(reinterpret_cast<uintptr_t>(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<size_t>(w_);
const auto h = static_cast<size_t>(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<uint8_t> 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<size_t>(src_));
if (!src) throw "missing input";
const auto feats = ParseFeats(feats_);
const auto w = static_cast<size_t>(w_);
const auto h = static_cast<size_t>(h_);
const auto utime = static_cast<size_t>(utime_);
buf_.resize(w*h*4*feats.size()*utime);
frames_ = utime * feats.size();
const auto b_num_x = static_cast<size_t>(block_num_[0]);
const auto b_num_y = static_cast<size_t>(block_num_[1]);
const auto dst_bw = w/b_num_x;
const auto dst_bh = h/b_num_y;
std::vector<std::pair<uint8_t, uint8_t>> block_rgba(dst_bw*dst_bh*4);
const auto dst_bw_f = static_cast<float>(dst_bw);
const auto dst_bh_f = static_cast<float>(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<float>(bw);
const auto bh_f = static_cast<float>(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<float>(y) / dst_bh_f;
for (size_t x = 0; x < dst_bw; ++x) {
const auto xf = static_cast<float>(x) / dst_bw_f;
const auto srcx = static_cast<size_t>(bw_f*xf) + off_x;
const auto srcy = static_cast<size_t>(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<float>(bw);
const auto bh_f = static_cast<float>(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<float>(y) / dst_bh_f;
for (size_t x = 0; x < dst_bw; ++x) {
const auto xf = static_cast<float>(x) / dst_bw_f;
const auto srcx = static_cast<size_t>(bw_f*xf) + off_x;
const auto srcy = static_cast<size_t>(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<float>(bt) / static_cast<float>(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<float>(ptr->second-ptr->first);
const auto b = static_cast<float>(ptr->first);
*(dst_ptr++) = static_cast<uint8_t>(bt_f*a+b);
++ptr;
}
} else {
const auto xf = static_cast<float>(x) / static_cast<float>(w);
const auto yf = static_cast<float>(y) / static_cast<float>(h);
const auto src_x = static_cast<size_t>(static_cast<float>(frame.w)*xf);
const auto src_y = static_cast<size_t>(static_cast<float>(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<Feat> ParseFeats(const std::string& script) {
std::vector<Feat> 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<size_t>(idx), .type = *end, });
}
return ret;
}
};
}
} // namespace pg