matrixmap.h
1 #pragma once 2 3 #include <stdexcept> 4 #include <vector> 5 6 namespace piomatter { 7 8 using matrix_map = std::vector<int>; 9 10 enum orientation { normal, r180, ccw, cw }; 11 12 int orientation_normal(int width, int height, int x, int y) { 13 return x + width * y; 14 } 15 16 int orientation_r180(int width, int height, int x, int y) { 17 x = width - x - 1; 18 y = height - y - 1; 19 return orientation_normal(width, height, x, y); 20 } 21 22 int orientation_ccw(int width, int height, int x, int y) { 23 return orientation_normal(height, width, y, width - x - 1); 24 } 25 26 int orientation_cw(int width, int height, int x, int y) { 27 return orientation_normal(height, width, y - height - 1, x); 28 } 29 30 namespace { 31 template <typename Cb> 32 void submap(std::vector<int> &result, int width, int height, int start_x, 33 int dx, int count_x_in, int start_y, int dy, int count_y, 34 int half_panel_height, const Cb &cb) { 35 36 for (int y = start_y; count_y; count_y -= 2, y += dy) { 37 for (int x = start_x, count_x = count_x_in; count_x--; x += dx) { 38 result.push_back(cb(width, height, x, y)); 39 result.push_back(cb(width, height, x, y + dy * half_panel_height)); 40 } 41 } 42 } 43 } // namespace 44 45 template <typename Cb> 46 matrix_map make_matrixmap(size_t width, size_t height, size_t n_addr_lines, 47 bool serpentine, const Cb &cb) { 48 49 size_t panel_height = 2 << n_addr_lines; 50 if (height % panel_height != 0) { 51 throw std::range_error("Height does not evenly divide panel height"); 52 } 53 54 size_t half_panel_height = 1u << n_addr_lines; 55 size_t v_panels = height / panel_height; 56 size_t pixels_across = width * v_panels; 57 matrix_map result; 58 result.reserve(width * height); 59 60 for (size_t i = 0; i < half_panel_height; i++) { 61 for (size_t j = 0; j < pixels_across; j++) { 62 int panel_no = j / width; 63 int panel_idx = j % width; 64 int x, y0, y1; 65 66 if (serpentine && panel_no % 2) { 67 x = width - panel_idx - 1; 68 y0 = (panel_no + 1) * panel_height - i - 1; 69 y1 = (panel_no + 1) * panel_height - i - half_panel_height - 1; 70 } else { 71 x = panel_idx; 72 y0 = panel_no * panel_height + i; 73 y1 = panel_no * panel_height + i + half_panel_height; 74 } 75 result.push_back(cb(width, height, x, y0)); 76 result.push_back(cb(width, height, x, y1)); 77 } 78 } 79 80 return result; 81 } 82 83 struct matrix_geometry { 84 template <typename Cb> 85 matrix_geometry(size_t pixels_across, size_t n_addr_lines, int n_planes, 86 size_t width, size_t height, bool serpentine, const Cb &cb) 87 : pixels_across(pixels_across), n_addr_lines(n_addr_lines), 88 n_planes(n_planes), width(width), 89 height(height), map{make_matrixmap(width, height, n_addr_lines, 90 serpentine, cb)} { 91 size_t pixels_down = 2u << n_addr_lines; 92 if (map.size() != pixels_down * pixels_across) { 93 throw std::range_error( 94 "map size does not match calculated pixel count"); 95 } 96 } 97 size_t pixels_across, n_addr_lines; 98 int n_planes; 99 size_t width, height; 100 matrix_map map; 101 }; 102 } // namespace piomatter