diff options
Diffstat (limited to 'minui/graphics.cpp')
-rw-r--r-- | minui/graphics.cpp | 299 |
1 files changed, 264 insertions, 35 deletions
diff --git a/minui/graphics.cpp b/minui/graphics.cpp index 3bfce11d8..bb96af141 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -22,10 +22,16 @@ #include <memory> +#ifdef BOARD_USE_CUSTOM_RECOVERY_FONT +#include BOARD_USE_CUSTOM_RECOVERY_FONT +#else #include "font_10x18.h" +#endif + #include "graphics_adf.h" #include "graphics_drm.h" #include "graphics_fbdev.h" +#include "graphics_overlay.h" #include "minui/minui.h" static GRFont* gr_font = NULL; @@ -39,6 +45,10 @@ static unsigned char gr_current_r = 255; static unsigned char gr_current_g = 255; static unsigned char gr_current_b = 255; static unsigned char gr_current_a = 255; +static unsigned char rgb_555[2]; +static unsigned char gr_current_r5 = 31; +static unsigned char gr_current_g5 = 63; +static unsigned char gr_current_b5 = 31; static GRSurface* gr_draw = NULL; @@ -47,6 +57,18 @@ static bool outside(int x, int y) return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height; } +#ifdef TW_NO_MINUI_CUSTOM_FONTS +int gr_measure(const char *s) +{ + return gr_font->char_width * strlen(s); +} + +void gr_font_size(int *x, int *y) +{ + *x = gr_font->char_width; + *y = gr_font->char_height; +} +#else // TW_USE_MINUI_CUSTOM_FONTS const GRFont* gr_sys_font() { return gr_font; @@ -62,6 +84,31 @@ void gr_font_size(const GRFont* font, int *x, int *y) *x = font->char_width; *y = font->char_height; } +#endif // TW_NO_MINUI_CUSTOM_FONTS + +void blend_16bpp(unsigned char* px, unsigned r5, unsigned g5, unsigned b5, unsigned char a) +{ + unsigned char orig[2]; + orig[0] = px[0]; + orig[1] = px[1]; + + /* This code is a little easier to read + unsigned oldred = (orig[1] >> 3); + unsigned oldgreen = (((orig[0] >> 5) << 3) + (orig[1] & 0x7)); + unsigned oldblue = (orig[0] & 0x1F); + + unsigned newred = (oldred * (255-a) + r5 * a) / 255; + unsigned newgreen = (oldgreen * (255-a) + g5 * a) / 255; + unsigned newblue = (oldblue * (255-a) + b5 * a) / 255; + */ + + unsigned newred = ((orig[1] >> 3) * (255-a) + r5 * a) / 255; + unsigned newgreen = ((((orig[0] >> 5) << 3) + (orig[1] & 0x7)) * (255-a) + g5 * a) / 255; + unsigned newblue = ((orig[0] & 0x1F) * (255-a) + b5 * a) / 255; + + *px++ = (newgreen << 5) + (newblue); + *px++ = (newred << 3) + (newgreen >> 3); +} static void text_blend(unsigned char* src_p, int src_row_bytes, unsigned char* dst_p, int dst_row_bytes, @@ -74,20 +121,30 @@ static void text_blend(unsigned char* src_p, int src_row_bytes, unsigned char a = *sx++; if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255; if (a == 255) { - *px++ = gr_current_r; - *px++ = gr_current_g; - *px++ = gr_current_b; - px++; + if (gr_draw->pixel_bytes == 2) { + *px++ = rgb_555[0]; + *px++ = rgb_555[1]; + } else { + *px++ = gr_current_r; + *px++ = gr_current_g; + *px++ = gr_current_b; + px++; + } } else if (a > 0) { - *px = (*px * (255-a) + gr_current_r * a) / 255; - ++px; - *px = (*px * (255-a) + gr_current_g * a) / 255; - ++px; - *px = (*px * (255-a) + gr_current_b * a) / 255; - ++px; - ++px; + if (gr_draw->pixel_bytes == 2) { + blend_16bpp(px, gr_current_r5, gr_current_g5, gr_current_b5, a); + px += gr_draw->pixel_bytes; + } else { + *px = (*px * (255-a) + gr_current_r * a) / 255; + ++px; + *px = (*px * (255-a) + gr_current_g * a) / 255; + ++px; + *px = (*px * (255-a) + gr_current_b * a) / 255; + ++px; + ++px; + } } else { - px += 4; + px += gr_draw->pixel_bytes; } } src_p += src_row_bytes; @@ -95,6 +152,38 @@ static void text_blend(unsigned char* src_p, int src_row_bytes, } } +#ifdef TW_NO_MINUI_CUSTOM_FONTS +void gr_text(int x, int y, const char *s, bool bold) +{ + GRFont* font = gr_font; + + if (!font->texture || gr_current_a == 0) return; + + bold = bold && (font->texture->height != font->char_height); + + x += overscan_offset_x; + y += overscan_offset_y; + + unsigned char ch; + while ((ch = *s++)) { + if (outside(x, y) || outside(x+font->char_width-1, y+font->char_height-1)) break; + + if (ch < ' ' || ch > '~') { + ch = '?'; + } + + unsigned char* src_p = font->texture->data + ((ch - ' ') * font->char_width) + + (bold ? font->char_height * font->texture->row_bytes : 0); + unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; + + text_blend(src_p, font->texture->row_bytes, + dst_p, gr_draw->row_bytes, + font->char_width, font->char_height); + + x += font->char_width; + } +} +#else //TW_NO_MINUI_CUSTOM_FONTS void gr_text(const GRFont* font, int x, int y, const char *s, bool bold) { if (!font->texture || gr_current_a == 0) return; @@ -123,6 +212,7 @@ void gr_text(const GRFont* font, int x, int y, const char *s, bool bold) x += font->char_width; } } +#endif //TW_NO_MINUI_CUSTOM_FONTS void gr_texticon(int x, int y, GRSurface* icon) { if (icon == NULL) return; @@ -145,6 +235,16 @@ void gr_texticon(int x, int y, GRSurface* icon) { icon->width, icon->height); } +void gr_convert_rgb_555() +{ + gr_current_r5 = (((gr_current_r & 0xFF) * 0x1F) + 0x7F) / 0xFF; + gr_current_g5 = (((gr_current_g & 0xFF) * 0x3F) + 0x7F) / 0xFF; + gr_current_b5 = (((gr_current_b & 0xFF) * 0x1F) + 0x7F) / 0xFF; + + rgb_555[0] = (gr_current_g5 << 5) + (gr_current_b5); + rgb_555[1] = (gr_current_r5 << 3) + (gr_current_g5 >> 3); +} + void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) @@ -158,10 +258,19 @@ void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a gr_current_b = b; gr_current_a = a; #endif + if (gr_draw->pixel_bytes == 2) { + gr_convert_rgb_555(); + } } void gr_clear() { + if (gr_draw->pixel_bytes == 2) { + gr_fill(0, 0, gr_fb_width(), gr_fb_height()); + return; + } + + // This code only works on 32bpp devices if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) { memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes); } else { @@ -194,10 +303,15 @@ void gr_fill(int x1, int y1, int x2, int y2) for (y = y1; y < y2; ++y) { unsigned char* px = p; for (x = x1; x < x2; ++x) { - *px++ = gr_current_r; - *px++ = gr_current_g; - *px++ = gr_current_b; - px++; + if (gr_draw->pixel_bytes == 2) { + *px++ = rgb_555[0]; + *px++ = rgb_555[1]; + } else { + *px++ = gr_current_r; + *px++ = gr_current_g; + *px++ = gr_current_b; + px++; + } } p += gr_draw->row_bytes; } @@ -206,25 +320,74 @@ void gr_fill(int x1, int y1, int x2, int y2) for (y = y1; y < y2; ++y) { unsigned char* px = p; for (x = x1; x < x2; ++x) { - *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255; - ++px; - *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255; - ++px; - *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255; - ++px; - ++px; + if (gr_draw->pixel_bytes == 2) { + blend_16bpp(px, gr_current_r5, gr_current_g5, gr_current_b5, gr_current_a); + px += gr_draw->row_bytes; + } else { + *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255; + ++px; + *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255; + ++px; + *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255; + ++px; + ++px; + } } p += gr_draw->row_bytes; } } } +void gr_blit_32to16(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) { + dx += overscan_offset_x; + dy += overscan_offset_y; + + if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return; + + unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes; + unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes; + + int i, j; + for (i = 0; i < h; ++i) { + unsigned char* spx = src_p; + unsigned char* dpx = dst_p; + + for (j = 0; j < w; ++j) { + unsigned a = spx[3]; + + if (a == 0) { + spx += source->pixel_bytes; + dpx += gr_draw->pixel_bytes; + } else { + unsigned r5 = (((*spx++ & 0xFF) * 0x1F) + 0x7F) / 0xFF; + unsigned g5 = (((*spx++ & 0xFF) * 0x3F) + 0x7F) / 0xFF; + unsigned b5 = (((*spx++ & 0xFF) * 0x1F) + 0x7F) / 0xFF; + spx++; + if (a == 255) { + *dpx++ = (g5 << 5) + (b5); + *dpx++ = (r5 << 3) + (g5 >> 3); + } else { + blend_16bpp(dpx, r5, g5, b5, a); + spx += source->pixel_bytes; + } + } + } + src_p += source->row_bytes; + dst_p += gr_draw->row_bytes; + } +} + void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) { if (source == NULL) return; if (gr_draw->pixel_bytes != source->pixel_bytes) { - printf("gr_blit: source has wrong format\n"); - return; + if (gr_draw->pixel_bytes == 2 && source->pixel_bytes == 4) { + gr_blit_32to16(source, sx, sy, w, h, dx, dy); + return; + } else { + printf("gr_blit: source has wrong format\n"); + return; + } } dx += overscan_offset_x; @@ -257,6 +420,49 @@ unsigned int gr_get_height(GRSurface* surface) { return surface->height; } +#ifdef TW_NO_MINUI_CUSTOM_FONTS +static void gr_init_font(void) +{ + gr_font = reinterpret_cast<GRFont*>(calloc(sizeof(*gr_font), 1)); + + int res = res_create_alpha_surface("font", &(gr_font->texture)); + if (res == 0) { + // The font image should be a 96x2 array of character images. The + // columns are the printable ASCII characters 0x20 - 0x7f. The + // top row is regular text; the bottom row is bold. + gr_font->char_width = gr_font->texture->width / 96; + gr_font->char_height = gr_font->texture->height / 2; + } else { + printf("failed to read font: res=%d\n", res); + + // fall back to the compiled-in font. + gr_font->texture = reinterpret_cast<GRSurface*>(malloc(sizeof(*gr_font->texture))); + gr_font->texture->width = font.width; + gr_font->texture->height = font.height; + gr_font->texture->row_bytes = font.width; + gr_font->texture->pixel_bytes = 1; + + unsigned char* bits = reinterpret_cast<unsigned char*>(malloc(font.width * font.height)); + gr_font->texture->data = reinterpret_cast<unsigned char*>(bits); + + unsigned char data; + unsigned char* in = font.rundata; + while((data = *in++)) { + memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f); + bits += (data & 0x7f); + } + + gr_font->char_width = font.char_width; + gr_font->char_height = font.char_height; + } +} + +void gr_set_font(__attribute__ ((unused))const char* name) { + //this cm function is made to change font. Don't care, just init the font: + gr_init_font(); + return; +} +#else // TW_NO_MINUI_CUSTOM_FONTS int gr_init_font(const char* name, GRFont** dest) { GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font))); if (font == nullptr) { @@ -311,26 +517,49 @@ static void gr_init_font(void) gr_font->char_width = font.char_width; gr_font->char_height = font.char_height; } +#endif // TW_NO_MINUI_CUSTOM_FONTS void gr_flip() { gr_draw = gr_backend->Flip(); } -int gr_init() { +int gr_init(void) +{ gr_init_font(); - auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendAdf>() }; + auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendOverlay>() }; gr_draw = backend->Init(); - if (!gr_draw) { - backend = std::make_unique<MinuiBackendDrm>(); - gr_draw = backend->Init(); - } +#ifdef MSM_BSP + if (gr_draw) { + printf("Using overlay graphics.\n"); + } +#endif - if (!gr_draw) { - backend = std::make_unique<MinuiBackendFbdev>(); - gr_draw = backend->Init(); - } +#ifndef MSM_BSP + if (!gr_draw) { + backend = std::make_unique<MinuiBackendAdf>(); + gr_draw = backend->Init(); + if (gr_draw) + printf("Using adf graphics.\n"); + } +#else + printf("Skipping adf graphics because TW_TARGET_USES_QCOM_BSP := true\n"); +#endif + + if (!gr_draw) { + backend = std::make_unique<MinuiBackendDrm>(); + gr_draw = backend->Init(); + if (gr_draw) + printf("Using drm graphics.\n"); + } + + if (!gr_draw) { + backend = std::make_unique<MinuiBackendFbdev>(); + gr_draw = backend->Init(); + if (gr_draw) + printf("Using fbdev graphics.\n"); + } if (!gr_draw) { return -1; |