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.

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