#include "bit_container.h" #include "common/utils.h" #include "core/exception.h" #include "imgui/imgui_image.h" #include "logger.h" #include #include #include #include #ifdef _WIN32 #define __USE_FILE_OFFSET64 #include "libs/mmap_windows.h" #else #include #include #endif namespace satdump { BitContainer::BitContainer(std::string name, std::string file_path, std::vector frms) : d_name(name), d_filepath(file_path), frames(frms) { // Generate unique ID std::random_device dev; std::mt19937 rng(dev()); std::uniform_int_distribution check(65, 90); for (size_t i = 0; i < 15; i++) unique_id[i] = check(rng); // Buffer for creating textures wip_texture_buffer = new uint32_t[d_chunk_size * d_chunk_size]; // Init mmap pointers d_file_memory_size = getFilesize(file_path); if (d_file_memory_size == 0) throw satdump_exception("Empty File!"); fd = open(file_path.c_str(), O_RDONLY); d_file_memory_ptr = (uint8_t *)mmap(0, d_file_memory_size, PROT_READ, MAP_SHARED, fd, 0); if (d_file_memory_ptr == MAP_FAILED) { close(fd); throw satdump_exception("mmap failed! (" + file_path + ")"); } d_frame_mode = frames.size(); logger->critical("Frame mode? %d", d_frame_mode); // Default period init_display(); // Initial start update = true; } BitContainer::~BitContainer() { delete[] wip_texture_buffer; munmap(d_file_memory_ptr, d_file_memory_size); close(fd); if (d_is_temporary && std::filesystem::exists(d_filepath)) { try { std::filesystem::remove(d_filepath); } catch (std::exception &e) { logger->warn("Failed to delete temporary file: %s", e.what()); } } } void BitContainer::init_display() { if (d_display_mode > 0) d_display_bits = 8; // Ensure chunk size is a multiple of display depth d_chunk_size = 512; if (d_display_bits > 1 && (d_chunk_size % d_display_bits != 0)) d_chunk_size += d_display_bits - (d_chunk_size % d_display_bits); logger->debug("Using chunksize : %d", d_chunk_size); // Init chunk count in X/Y if (d_frame_mode) { img_parts_y = (frames.size() / d_chunk_size) + 1; size_t max_size = 0; for (auto &f : frames) if (f.size > max_size) max_size = f.size; img_parts_x = (max_size / d_chunk_size) + 1; } else { size_t final_size = 0; img_parts_y = 0; while (final_size < d_file_memory_size * 8) { final_size += d_bitperiod * d_chunk_size; img_parts_y++; } final_size = 0; img_parts_x = 0; while (final_size < d_bitperiod) { final_size += d_chunk_size; img_parts_x++; } } image_parts.resize(img_parts_y * img_parts_x); printf("%d %d\n", int(img_parts_x * d_chunk_size), int(img_parts_y * d_chunk_size)); // Ensure we force update for (auto &p : image_parts) p.need_update = true; force_update_all = true; } void BitContainer::doUpdateTextures() { if (force_update_all) { for (size_t ii = 0; ii < img_parts_y; ii++) { for (size_t iii = 0; iii < img_parts_x; iii++) { auto &part = image_parts[ii * img_parts_x + iii]; if (part.image_id != 0) deleteImageTexture(part.image_id); } } force_update_all = false; update = true; } const int max_update_num = 2; int updated_num = 0; if (update) { size_t offset = 0; for (size_t ii = 0; ii < img_parts_y; ii++) { for (size_t iii = 0; iii < img_parts_x; iii++) { auto &part = image_parts[ii * img_parts_x + iii]; if (!part.need_update) continue; part.need_update = false; size_t xoffset = iii * d_chunk_size; if (part.visible) { // Only generation is slow, deleting a texture is fast updated_num++; if (part.image_id == 0) part.image_id = makeImageTexture(); renderSegment(part, ii, iii, xoffset, offset); } else { if (part.image_id != 0) deleteImageTexture(part.image_id); part.image_id = 0; } part.pos1_x = d_chunk_size * (iii + 0); part.pos1_y = d_chunk_size * (ii + 1); part.pos2_x = d_chunk_size * (iii + 1); part.pos2_y = d_chunk_size * (ii + 0); part.i = ii * img_parts_x + iii; if (updated_num >= max_update_num) return; // TODOREWORK? } offset += d_bitperiod * d_chunk_size; } update = false; } } void BitContainer::doDrawPlotTextures(ImPlotRect c) { for (auto &part : image_parts) { if (part.i == -1) { part.need_update = true; continue; } bool status_before = part.visible; part.visible = false; if (c.Min().x > part.pos2_x || c.Max().y < part.pos2_y) {} else if (c.Max().x < part.pos1_x || c.Min().y > part.pos1_y) {} else if (!part.need_update) { // printf("%f %f - %f %f ---- %f %f - %f %f ---- %d\n", // c.Min().x, c.Min().y, c.Max().x, c.Max().y, // part.pos1_x, part.pos1_y, part.pos2_x, part.pos2_y, // part.i); ImPlot::PlotImage("Test", (void *)(intptr_t)part.image_id, {part.pos1_x, part.pos1_y}, {part.pos2_x, part.pos2_y}); part.visible = true; } if (part.visible != status_before) { part.need_update = true; update = true; } } } } // namespace satdump