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.

154 lines
4.6 KiB

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