General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
3.7 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #pragma once
  2. #include "gp/function.hpp"
  3. #include "gp/buffer.hpp"
  4. #include "gp/math.hpp"
  5. #include "gp/bitops.hpp"
  6. #include "gp/algorithm/tmp_manip.hpp"
  7. #include <iostream>
  8. namespace gp{
  9. template<bool lazy, typename color_type, typename allocator>
  10. class bmp_viewport {
  11. public:
  12. using src_t = typename gp::either<lazy,
  13. gp::function<color_type(gp::vec2_g<int32_t>), allocator>,
  14. gp::buffer<gp::buffer<color_type>>
  15. >::type;
  16. private:
  17. src_t source;
  18. gp::vec2_g<int32_t> resolution;
  19. color_type get(int32_t x, int32_t y) {
  20. gp_config::assertion(x>=0, "getting an x below zero");
  21. gp_config::assertion(y>=0, "getting an y below zero");
  22. if constexpr (lazy) {
  23. return source({x, y});
  24. } else {
  25. return source[x][y];
  26. }
  27. }
  28. public:
  29. bmp_viewport(gp::vec2_g<int32_t> res, src_t src)
  30. : source{src}
  31. , resolution{res}
  32. {}
  33. gp::buffer<char>::associated_iterator write(gp::buffer<char> destination) {
  34. using sle16 = gp::endian_wrapper<int16_t, gp::endian::little>;
  35. using sbe16 = gp::endian_wrapper<int16_t, gp::endian::big>;
  36. using sle32 = gp::endian_wrapper<int32_t, gp::endian::little>;
  37. using sbe32 = gp::endian_wrapper<int32_t, gp::endian::big>;
  38. auto it = destination.begin();
  39. *(it++) = 'B';
  40. *(it++) = 'M';
  41. auto& filesize = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  42. it = it+4;
  43. *(it++) = 0;
  44. *(it++) = 0;
  45. *(it++) = 0;
  46. *(it++) = 0;
  47. auto& pixel_array_offset = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  48. it = it+4;
  49. auto dib_start = it;
  50. auto& dibsize = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  51. it = it+4;
  52. auto& width = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  53. width = resolution.x;
  54. it = it+4;
  55. auto& height = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  56. it = it+4;
  57. height = resolution.y;
  58. auto& plane_cnt = gp::buffer<char>{it.data, (it+2).data}.cast<sle16>()[0];
  59. it = it+2;
  60. plane_cnt = 1;
  61. auto& bit_per_pixel = gp::buffer<char>{it.data, (it+2).data}.cast<sle16>()[0];
  62. it = it+2;
  63. bit_per_pixel = sizeof(color_type)*8; // TODO: correct the size
  64. auto& compression_method = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  65. it = it+4;
  66. compression_method = 0;
  67. auto& image_size = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  68. it = it+4;
  69. auto& h_pixel_per_meter = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  70. it = it+4;
  71. h_pixel_per_meter = 2835;
  72. auto& v_pixel_per_meter = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  73. it = it+4;
  74. v_pixel_per_meter = 2835;
  75. auto& colors_in_palette = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  76. it = it+4;
  77. colors_in_palette = 0;
  78. auto& important_colors = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  79. it = it+4;
  80. important_colors = 0;
  81. auto dib_end = it;
  82. dibsize = dib_end - dib_start;
  83. auto pixel_array_start = it;
  84. for(int32_t line = resolution.y - 1; line >= 0; line--)
  85. {
  86. int32_t len = 0;
  87. for(int32_t row = 0; row < resolution.x; row++)
  88. {
  89. // TODO: add more default color modes
  90. if constexpr (std::is_same<color_type, gp::vec4_g<uint8_t>>::value)
  91. {
  92. auto color = get(row, line);
  93. *(it++) = color.b();
  94. *(it++) = color.g();
  95. *(it++) = color.r();
  96. *(it++) = color.a();
  97. } else {
  98. it = it + sizeof(color_type);
  99. }
  100. len+=sizeof(color_type);
  101. }
  102. for(;len % 4; ++len)
  103. {
  104. *(it++) = 0;
  105. }
  106. }
  107. auto pixel_array_end = it;
  108. pixel_array_offset = pixel_array_start - destination.begin();
  109. filesize = pixel_array_end - destination.begin();
  110. image_size = pixel_array_end - pixel_array_start;
  111. return it;
  112. }
  113. };
  114. }