General Purpose library for Freestanding C++ and POSIX systems
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

130 行
3.7 KiB

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