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.

156 lines
4.6 KiB

пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
  1. #pragma once
  2. #include "gp/algorithm/tmp_manip.hpp"
  3. #include "gp/bitops.hpp"
  4. #include "gp/buffer.hpp"
  5. #include "gp/function.hpp"
  6. #include "gp/math.hpp"
  7. #include <iostream>
  8. namespace gp{
  9. /**
  10. * @brief A bmp format viewport that can be used to generate and export bmp file contents
  11. *
  12. * @tparam lazy if true, will expect the source to be a function, else would expect it to be a buffer
  13. * @tparam color_type the type that represents the color. as of now only gp::vec4_g<uint8_t> is supported
  14. */
  15. template<bool lazy, typename color_type>
  16. class bmp_viewport {
  17. public:
  18. /**
  19. * @brief The type of data source expected
  20. */
  21. using src_t = typename gp::either<lazy,
  22. gp::function<color_type(gp::vec2_g<int32_t>)>,
  23. gp::buffer<gp::buffer<color_type>>
  24. >::type;
  25. private:
  26. src_t source;
  27. gp::vec2_g<int32_t> resolution;
  28. color_type get(int32_t x, int32_t y) {
  29. gp_config::assertion(x>=0, "getting an x below zero");
  30. gp_config::assertion(y>=0, "getting an y below zero");
  31. if constexpr (lazy) {
  32. return source({x, y});
  33. } else {
  34. return source[x][y];
  35. }
  36. }
  37. public:
  38. /**
  39. * @brief Construct a new bmp viewport object
  40. *
  41. * @param res The viewport size in pixels
  42. * @param src The viewport source @see src_t
  43. */
  44. bmp_viewport(gp::vec2_g<int32_t> res, src_t src)
  45. : source{src}
  46. , resolution{res}
  47. {}
  48. /**
  49. * @brief Wtrites the viewport into a buffer in the bmp file format
  50. *
  51. * Failure is not currently handled, hence more than enough buffer space is expected.
  52. *
  53. * @param destination a buffer wide enough to write the entire data on it at once
  54. * @return gp::buffer<char>::associated_iterator the byte after the last one that was written by the function
  55. */
  56. gp::buffer<char>::associated_iterator write(gp::buffer<char> destination) {
  57. using sle16 = gp::endian_wrapper<int16_t, gp::endian::little>;
  58. using sbe16 = gp::endian_wrapper<int16_t, gp::endian::big>;
  59. using sle32 = gp::endian_wrapper<int32_t, gp::endian::little>;
  60. using sbe32 = gp::endian_wrapper<int32_t, gp::endian::big>;
  61. auto it = destination.begin();
  62. *(it++) = 'B';
  63. *(it++) = 'M';
  64. auto& filesize = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  65. it = it+4;
  66. *(it++) = 0;
  67. *(it++) = 0;
  68. *(it++) = 0;
  69. *(it++) = 0;
  70. auto& pixel_array_offset = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  71. it = it+4;
  72. auto dib_start = it;
  73. auto& dibsize = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  74. it = it+4;
  75. auto& width = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  76. width = resolution.x;
  77. it = it+4;
  78. auto& height = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  79. it = it+4;
  80. height = resolution.y;
  81. auto& plane_cnt = gp::buffer<char>{it.data, (it+2).data}.cast<sle16>()[0];
  82. it = it+2;
  83. plane_cnt = 1;
  84. auto& bit_per_pixel = gp::buffer<char>{it.data, (it+2).data}.cast<sle16>()[0];
  85. it = it+2;
  86. bit_per_pixel = sizeof(color_type)*8; // TODO: correct the size
  87. auto& compression_method = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  88. it = it+4;
  89. compression_method = 0;
  90. auto& image_size = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  91. it = it+4;
  92. auto& h_pixel_per_meter = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  93. it = it+4;
  94. h_pixel_per_meter = 2835;
  95. auto& v_pixel_per_meter = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  96. it = it+4;
  97. v_pixel_per_meter = 2835;
  98. auto& colors_in_palette = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  99. it = it+4;
  100. colors_in_palette = 0;
  101. auto& important_colors = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
  102. it = it+4;
  103. important_colors = 0;
  104. auto dib_end = it;
  105. dibsize = dib_end - dib_start;
  106. auto pixel_array_start = it;
  107. for(int32_t line = resolution.y - 1; line >= 0; line--)
  108. {
  109. int32_t len = 0;
  110. for(int32_t row = 0; row < resolution.x; row++)
  111. {
  112. // TODO: add more default color modes
  113. if constexpr (std::is_same<color_type, gp::vec4_g<uint8_t>>::value)
  114. {
  115. auto color = get(row, line);
  116. *(it++) = color.b();
  117. *(it++) = color.g();
  118. *(it++) = color.r();
  119. *(it++) = color.a();
  120. } else {
  121. it = it + sizeof(color_type);
  122. }
  123. len+=sizeof(color_type);
  124. }
  125. for(;len % 4; ++len)
  126. {
  127. *(it++) = 0;
  128. }
  129. }
  130. auto pixel_array_end = it;
  131. pixel_array_offset = pixel_array_start - destination.begin();
  132. filesize = pixel_array_end - destination.begin();
  133. image_size = pixel_array_end - pixel_array_start;
  134. return it;
  135. }
  136. };
  137. }