#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 namespace gp{ template class bmp_viewport { public: using src_t = typename gp::either), allocator>, gp::buffer> >::type; private: src_t source; gp::vec2_g 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: bmp_viewport(gp::vec2_g res, src_t src) : source{src} , resolution{res} {} gp::buffer::associated_iterator write(gp::buffer destination) { using sle16 = gp::endian_wrapper; using sbe16 = gp::endian_wrapper; using sle32 = gp::endian_wrapper; using sbe32 = gp::endian_wrapper; auto it = destination.begin(); *(it++) = 'B'; *(it++) = 'M'; auto& filesize = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; *(it++) = 0; *(it++) = 0; *(it++) = 0; *(it++) = 0; auto& pixel_array_offset = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; auto dib_start = it; auto& dibsize = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; auto& width = gp::buffer{it.data, (it+4).data}.cast()[0]; width = resolution.x; it = it+4; auto& height = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; height = resolution.y; auto& plane_cnt = gp::buffer{it.data, (it+2).data}.cast()[0]; it = it+2; plane_cnt = 1; auto& bit_per_pixel = gp::buffer{it.data, (it+2).data}.cast()[0]; it = it+2; bit_per_pixel = sizeof(color_type)*8; // TODO: correct the size auto& compression_method = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; compression_method = 0; auto& image_size = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; auto& h_pixel_per_meter = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; h_pixel_per_meter = 2835; auto& v_pixel_per_meter = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; v_pixel_per_meter = 2835; auto& colors_in_palette = gp::buffer{it.data, (it+4).data}.cast()[0]; it = it+4; colors_in_palette = 0; auto& important_colors = gp::buffer{it.data, (it+4).data}.cast()[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>::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; } }; }