bitmap.hpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #ifndef BITMAP_HPP
  2. #define BITMAP_HPP
  3. #include "implementation.h"
  4. #include "utils.hpp"
  5. template <int width, int height>
  6. class bitmap_data
  7. {
  8. public:
  9. static constexpr int2 size = int2{width, height}; // this should be a template parameter
  10. using bitset = std::bitset<size.x() * size.y()>;
  11. bitset bits;
  12. };
  13. template <int width, int height>
  14. class bitmap : public movable_bounds, public i_graphic, public i_ui_object
  15. {
  16. public:
  17. using bit_data = bitmap_data<width, height>;
  18. bitmap(const bit_data& data, graphical::color color, range2D bounds) :
  19. movable_bounds(bounds), dim(), align(), data(&data), color(color)
  20. {
  21. calculate_padding();
  22. }
  23. void draw(const graphical::surface& surface)
  24. {
  25. const auto size = bit_data::size;
  26. const auto cell_size = (bounds.upper() - bounds.lower())/size;
  27. // alignment logic
  28. assert(to_conjunction( (align == -int2::one()) | (align == int2::zero()) | (align == int2::one()) ));
  29. const int2 lower_mask (align == -int2::one());
  30. const auto upper_mask = 1 - lower_mask;
  31. const auto align_offset = cell_size * align * (lower_mask * padding.lower() + upper_mask * padding.upper());
  32. auto cell = int2::zero();
  33. auto dimension = cell.begin();
  34. while(dimension != cell.end())
  35. {
  36. if(get_bit(cell))
  37. {
  38. rect cell_rect {cell_size, bounds.lower() + cell*cell_size};
  39. cell_rect.position += align_offset;
  40. if(not(dim <= int2::zero()))
  41. {
  42. lowlight(surface, color, cell_rect, dim);
  43. }
  44. else
  45. {
  46. fill(surface, color, cell_rect);
  47. }
  48. }
  49. dimension = support::advance_vector(cell, int2::zero(), size);
  50. }
  51. }
  52. void set_data(const bit_data& new_data)
  53. {
  54. if(data != &new_data)
  55. {
  56. data = &new_data;
  57. calculate_padding();
  58. }
  59. }
  60. int2 dim;
  61. int2 align;
  62. private:
  63. const bit_data* data;
  64. graphical::color color;
  65. range2D padding;
  66. void calculate_padding()
  67. {
  68. // inefficient, but shouldn't happen very often,
  69. // don't generalize this as is though
  70. auto cell = int2::zero();
  71. auto dimension = cell.begin();
  72. auto cropped = invalid_range;
  73. while(dimension != cell.end())
  74. {
  75. if(get_bit(cell))
  76. {
  77. cropped.upper().max(cell);
  78. cropped.lower().min(cell);
  79. }
  80. dimension = support::advance_vector(cell, int2::zero(), bit_data::size);
  81. }
  82. padding.lower() = cropped.lower();
  83. padding.upper() = bit_data::size - 1 - cropped.upper(); // ugly -1 cause bits have width
  84. }
  85. bool get_bit(int2 cell)
  86. {
  87. return data->bits[data->bits.size()-1 - (cell.y() * bit_data::size.x() + cell.x())];
  88. }
  89. };
  90. template <int width, int height>
  91. bitmap(const bitmap_data<width, height>&, range2D, graphical::color)
  92. -> bitmap<width, height>;
  93. #endif /* end of include guard */