#include #include using namespace std; namespace kms { void draw_rgb_pixel(IFramebuffer& buf, unsigned x, unsigned y, RGB color) { if (x >= buf.width() || y >= buf.height()) throw runtime_error("attempt to draw outside the buffer"); switch (buf.format()) { case PixelFormat::XRGB8888: case PixelFormat::ARGB8888: { uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4); *p = color.argb8888(); break; } case PixelFormat::XBGR8888: case PixelFormat::ABGR8888: { uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4); *p = color.abgr8888(); break; } case PixelFormat::RGB888: { uint8_t *p = buf.map(0) + buf.stride(0) * y + x * 3; p[0] = color.b; p[1] = color.g; p[2] = color.r; break; } case PixelFormat::BGR888: { uint8_t *p = buf.map(0) + buf.stride(0) * y + x * 3; p[0] = color.r; p[1] = color.g; p[2] = color.b; break; } case PixelFormat::RGB565: { uint16_t *p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2); *p = color.rgb565(); break; } case PixelFormat::BGR565: { uint16_t *p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2); *p = color.bgr565(); break; } default: throw std::invalid_argument("invalid pixelformat"); } } void draw_yuv422_macropixel(IFramebuffer& buf, unsigned x, unsigned y, YUV yuv1, YUV yuv2) { if ((x + 1) >= buf.width() || y >= buf.height()) throw runtime_error("attempt to draw outside the buffer"); ASSERT((x & 1) == 0); uint8_t *p = (uint8_t*)(buf.map(0) + buf.stride(0) * y + x * 2); uint8_t y0 = yuv1.y; uint8_t y1 = yuv2.y; uint8_t u = (yuv1.u + yuv2.u) / 2; uint8_t v = (yuv1.v + yuv2.v) / 2; switch (buf.format()) { case PixelFormat::UYVY: p[0] = u; p[1] = y0; p[2] = v; p[3] = y1; break; case PixelFormat::YUYV: p[0] = y0; p[1] = u; p[2] = y1; p[3] = v; break; case PixelFormat::YVYU: p[0] = y0; p[1] = v; p[2] = y1; p[3] = u; break; case PixelFormat::VYUY: p[0] = v; p[1] = y0; p[2] = u; p[3] = y1; break; default: throw std::invalid_argument("invalid pixelformat"); } } void draw_yuv420_macropixel(IFramebuffer& buf, unsigned x, unsigned y, YUV yuv1, YUV yuv2, YUV yuv3, YUV yuv4) { if ((x + 1) >= buf.width() || (y + 1) >= buf.height()) throw runtime_error("attempt to draw outside the buffer"); ASSERT((x & 1) == 0); ASSERT((y & 1) == 0); uint8_t *py1 = (uint8_t*)(buf.map(0) + buf.stride(0) * (y + 0) + x); uint8_t *py2 = (uint8_t*)(buf.map(0) + buf.stride(0) * (y + 1) + x); uint8_t *puv = (uint8_t*)(buf.map(1) + buf.stride(1) * (y / 2) + x); uint8_t y0 = yuv1.y; uint8_t y1 = yuv2.y; uint8_t y2 = yuv3.y; uint8_t y3 = yuv4.y; uint8_t u = (yuv1.u + yuv2.u + yuv3.u + yuv4.u) / 4; uint8_t v = (yuv1.v + yuv2.v + yuv3.v + yuv4.v) / 4; switch (buf.format()) { case PixelFormat::NV12: py1[0] = y0; py1[1] = y1; py2[0] = y2; py2[1] = y3; puv[0] = u; puv[1] = v; break; case PixelFormat::NV21: py1[0] = y0; py1[1] = y1; py2[0] = y2; py2[1] = y3; puv[0] = v; puv[1] = u; break; default: throw std::invalid_argument("invalid pixelformat"); } } void draw_rect(IFramebuffer &fb, uint32_t x, uint32_t y, uint32_t w, uint32_t h, RGB color) { unsigned i, j; YUV yuvcolor = color.yuv(); switch (fb.format()) { case PixelFormat::XRGB8888: case PixelFormat::XBGR8888: case PixelFormat::ARGB8888: case PixelFormat::ABGR8888: case PixelFormat::RGB888: case PixelFormat::BGR888: case PixelFormat::RGB565: case PixelFormat::BGR565: for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { draw_rgb_pixel(fb, x + i, y + j, color); } } break; case PixelFormat::UYVY: case PixelFormat::YUYV: case PixelFormat::YVYU: case PixelFormat::VYUY: for (j = 0; j < h; j++) { for (i = 0; i < w; i += 2) { draw_yuv422_macropixel(fb, x + i, y + j, yuvcolor, yuvcolor); } } break; case PixelFormat::NV12: case PixelFormat::NV21: for (j = 0; j < h; j += 2) { for (i = 0; i < w; i += 2) { draw_yuv420_macropixel(fb, x + i, y + j, yuvcolor, yuvcolor, yuvcolor, yuvcolor); } } break; default: throw std::invalid_argument("unknown pixelformat"); } } static bool get_char_pixel(char c, uint32_t x, uint32_t y) { #include "font_8x8.h" uint8_t bits = fontdata_8x8[8 * c + y]; bool bit = (bits >> (7 - x)) & 1; return bit; } static void draw_char(IFramebuffer& buf, uint32_t xpos, uint32_t ypos, char c, RGB color) { unsigned x, y; YUV yuvcolor = color.yuv(); switch (buf.format()) { case PixelFormat::XRGB8888: case PixelFormat::XBGR8888: case PixelFormat::ARGB8888: case PixelFormat::ABGR8888: case PixelFormat::RGB888: case PixelFormat::BGR888: case PixelFormat::RGB565: case PixelFormat::BGR565: for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { bool b = get_char_pixel(c, x, y); draw_rgb_pixel(buf, xpos + x, ypos + y, b ? color : RGB()); } } break; case PixelFormat::UYVY: case PixelFormat::YUYV: case PixelFormat::YVYU: case PixelFormat::VYUY: for (y = 0; y < 8; y++) { for (x = 0; x < 8; x += 2) { bool b0 = get_char_pixel(c, x, y); bool b1 = get_char_pixel(c, x + 1, y); draw_yuv422_macropixel(buf, xpos + x, ypos + y, b0 ? yuvcolor : YUV(RGB()), b1 ? yuvcolor : YUV(RGB())); } } break; case PixelFormat::NV12: case PixelFormat::NV21: for (y = 0; y < 8; y += 2) { for (x = 0; x < 8; x += 2) { bool b00 = get_char_pixel(c, x, y); bool b10 = get_char_pixel(c, x + 1, y); bool b01 = get_char_pixel(c, x, y + 1); bool b11 = get_char_pixel(c, x + 1, y + 1); draw_yuv420_macropixel(buf, xpos + x, ypos + y, b00 ? yuvcolor : YUV(RGB()), b10 ? yuvcolor : YUV(RGB()), b01 ? yuvcolor : YUV(RGB()), b11 ? yuvcolor : YUV(RGB())); } } break; default: throw std::invalid_argument("unknown pixelformat"); } } void draw_text(IFramebuffer& buf, uint32_t x, uint32_t y, const string& str, RGB color) { for(unsigned i = 0; i < str.size(); i++) draw_char(buf, (x + 8 * i), y, str[i], color); } }