|
|
- #pragma once
-
- #include "gp/algorithm/tmp_manip.hpp"
- #include "gp/bitops.hpp"
- #include "gp/buffer.hpp"
- #include "gp/function.hpp"
- #include "gp/math.hpp"
-
-
- #include <iostream>
-
- namespace gp{
- /**
- * @brief A bmp format viewport that can be used to generate and export bmp file contents
- *
- * @tparam lazy if true, will expect the source to be a function, else would expect it to be a buffer
- * @tparam color_type the type that represents the color. as of now only gp::vec4_g<uint8_t> is supported
- */
- template<bool lazy, typename color_type>
- class bmp_viewport {
- public:
- /**
- * @brief The type of data source expected
- */
- using src_t = typename gp::either<lazy,
- gp::function<color_type(gp::vec2_g<int32_t>)>,
- gp::buffer<gp::buffer<color_type>>
- >::type;
- private:
- src_t source;
- gp::vec2_g<int32_t> resolution;
- color_type get(int32_t x, int32_t y) {
- gp_config::assertion(x>=0, "getting an x below zero");
- gp_config::assertion(y>=0, "getting an y below zero");
-
- if constexpr (lazy) {
- return source({x, y});
- } else {
- return source[x][y];
- }
- }
- public:
- /**
- * @brief Construct a new bmp viewport object
- *
- * @param res The viewport size in pixels
- * @param src The viewport source @see src_t
- */
- bmp_viewport(gp::vec2_g<int32_t> res, src_t src)
- : source{src}
- , resolution{res}
- {}
-
- /**
- * @brief Wtrites the viewport into a buffer in the bmp file format
- *
- * Failure is not currently handled, hence more than enough buffer space is expected.
- *
- * @param destination a buffer wide enough to write the entire data on it at once
- * @return gp::buffer<char>::associated_iterator the byte after the last one that was written by the function
- */
- gp::buffer<char>::associated_iterator write(gp::buffer<char> destination) {
- using sle16 = gp::endian_wrapper<int16_t, gp::endian::little>;
- using sbe16 = gp::endian_wrapper<int16_t, gp::endian::big>;
- using sle32 = gp::endian_wrapper<int32_t, gp::endian::little>;
- using sbe32 = gp::endian_wrapper<int32_t, gp::endian::big>;
-
- auto it = destination.begin();
- *(it++) = 'B';
- *(it++) = 'M';
- auto& filesize = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
-
- *(it++) = 0;
- *(it++) = 0;
- *(it++) = 0;
- *(it++) = 0;
- auto& pixel_array_offset = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
-
- auto dib_start = it;
-
- auto& dibsize = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
-
- auto& width = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- width = resolution.x;
- it = it+4;
- auto& height = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
- height = resolution.y;
-
- auto& plane_cnt = gp::buffer<char>{it.data, (it+2).data}.cast<sle16>()[0];
- it = it+2;
- plane_cnt = 1;
- auto& bit_per_pixel = gp::buffer<char>{it.data, (it+2).data}.cast<sle16>()[0];
- it = it+2;
- bit_per_pixel = sizeof(color_type)*8; // TODO: correct the size
-
- auto& compression_method = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
- compression_method = 0;
-
- auto& image_size = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
-
- auto& h_pixel_per_meter = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
- h_pixel_per_meter = 2835;
- auto& v_pixel_per_meter = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
- v_pixel_per_meter = 2835;
-
- auto& colors_in_palette = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
- colors_in_palette = 0;
- auto& important_colors = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
- it = it+4;
- important_colors = 0;
-
- auto dib_end = it;
- dibsize = dib_end - dib_start;
- auto pixel_array_start = it;
-
- for(int32_t line = resolution.y - 1; line >= 0; line--)
- {
- int32_t len = 0;
- for(int32_t row = 0; row < resolution.x; row++)
- {
- // TODO: add more default color modes
- if constexpr (std::is_same<color_type, gp::vec4_g<uint8_t>>::value)
- {
- auto color = get(row, line);
- *(it++) = color.b();
- *(it++) = color.g();
- *(it++) = color.r();
- *(it++) = color.a();
- } else {
- it = it + sizeof(color_type);
- }
- len+=sizeof(color_type);
- }
- for(;len % 4; ++len)
- {
- *(it++) = 0;
- }
- }
-
- auto pixel_array_end = it;
- pixel_array_offset = pixel_array_start - destination.begin();
- filesize = pixel_array_end - destination.begin();
- image_size = pixel_array_end - pixel_array_start;
-
- return it;
- }
- };
- }
|