xbanan/xbanan/Image.cpp

89 lines
2.6 KiB
C++

#include "Definitions.h"
#include "Image.h"
#include <X11/X.h>
void put_image(const PutImageInfo& info)
{
uint8_t in_bpp = 0;
for (const auto& format : g_formats)
if (format.depth == info.in_depth)
in_bpp = format.bitsPerPixel;
ASSERT(in_bpp && 32 % in_bpp == 0);
const auto min_x = BAN::Math::max<int32_t>(0, -info.out_x);
const auto min_y = BAN::Math::max<int32_t>(0, -info.out_y);
const auto max_x = BAN::Math::min<int32_t>(info.w, info.out_w - info.out_x);
const auto max_y = BAN::Math::min<int32_t>(info.h, info.out_h - info.out_y);
auto* out_data_u32 = static_cast<uint32_t*>(info.out_data);
const auto* in_data_u32 = static_cast<const uint32_t*>(info.in_data);
if (!(info.format == XYBitmap || info.in_depth == info.out_depth))
{
dwarnln("format {}, in depth {}, out depth {}", info.format, info.in_depth, info.out_depth);
ASSERT_NOT_REACHED();
}
switch (info.format)
{
case XYBitmap:
ASSERT(info.in_depth == 1);
[[fallthrough]];
case XYPixmap:
{
const auto dwords_per_plane = (info.left_pad + info.in_w + 31) / 32;
for (int32_t y = min_y; y < max_y; y++)
{
const auto dst_off = (info.out_y + y) * info.out_w + info.out_x;
for (int32_t x = min_x; x < max_x; x++)
{
const auto bit_index = info.left_pad + (info.in_y + y) * info.in_w + (info.in_x + x);
const auto dword = bit_index / 32;
const auto bit_mask = 1u << (bit_index % 32);
uint32_t pixel = 0;
for (size_t i = 0; i < info.in_depth; i++)
if (in_data_u32[dword + i * dwords_per_plane] & bit_mask)
pixel |= 1u << i;
out_data_u32[dst_off + x] = pixel;
}
}
break;
}
case ZPixmap:
{
ASSERT(info.left_pad == 0);
if (in_bpp == 32)
{
const auto bytes_per_row = (max_x - min_x) * 4;
for (int32_t y = min_y; y < max_y; y++)
{
const auto dst_off = (info.out_y + y) * info.out_w + (info.out_x + min_x);
const auto src_off = (info. in_y + y) * info. in_w + (info. in_x + min_y);
memcpy(&out_data_u32[dst_off], &in_data_u32[src_off], bytes_per_row);
}
}
else
{
const auto pixel_mask = (1u << info.in_depth) - 1;
const auto bits_per_scanline = (info.in_w * in_bpp + 31) / 32 * 32;
for (int32_t y = min_y; y < max_y; y++)
{
const auto dst_off = (info.out_y + y) * info.out_w + info.out_x;
for (int32_t x = min_x; x < max_x; x++)
{
const auto bit_offset = (info.in_y + y) * bits_per_scanline + (info.in_x + x) * in_bpp;
const auto dword = bit_offset / 32;
const auto shift = bit_offset % 32;
out_data_u32[dst_off + x] = (in_data_u32[dword] >> shift) & pixel_mask;
}
}
}
break;
}
default:
ASSERT_NOT_REACHED();
}
}