summaryrefslogtreecommitdiffstats
path: root/minui
diff options
context:
space:
mode:
Diffstat (limited to 'minui')
-rw-r--r--minui/Android.mk14
-rw-r--r--minui/graphics.c119
-rw-r--r--minui/minui.h6
-rw-r--r--minui/resources.c163
4 files changed, 255 insertions, 47 deletions
diff --git a/minui/Android.mk b/minui/Android.mk
index f9afd6ba9..232ebb2bf 100644
--- a/minui/Android.mk
+++ b/minui/Android.mk
@@ -9,11 +9,21 @@ LOCAL_C_INCLUDES +=\
LOCAL_STATIC_LIBRARY := libpng
LOCAL_MODULE := libminui
-ifeq ($(TARGET_RECOVERY_PIXEL_FORMAT),"RGBX_8888")
+# This used to compare against values in double-quotes (which are just
+# ordinary characters in this context). Strip double-quotes from the
+# value so that either will work.
+
+ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),RGBX_8888)
LOCAL_CFLAGS += -DRECOVERY_RGBX
endif
-ifeq ($(TARGET_RECOVERY_PIXEL_FORMAT),"BGRA_8888")
+ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),BGRA_8888)
LOCAL_CFLAGS += -DRECOVERY_BGRA
endif
+ifneq ($(TARGET_RECOVERY_OVERSCAN_PERCENT),)
+ LOCAL_CFLAGS += -DOVERSCAN_PERCENT=$(TARGET_RECOVERY_OVERSCAN_PERCENT)
+else
+ LOCAL_CFLAGS += -DOVERSCAN_PERCENT=0
+endif
+
include $(BUILD_STATIC_LIBRARY)
diff --git a/minui/graphics.c b/minui/graphics.c
index 296e2e078..4968eac7a 100644
--- a/minui/graphics.c
+++ b/minui/graphics.c
@@ -44,20 +44,24 @@
#define PIXEL_SIZE 2
#endif
+#define NUM_BUFFERS 2
+
typedef struct {
- GGLSurface texture;
+ GGLSurface* texture;
unsigned cwidth;
unsigned cheight;
- unsigned ascent;
} GRFont;
static GRFont *gr_font = 0;
static GGLContext *gr_context = 0;
static GGLSurface gr_font_texture;
-static GGLSurface gr_framebuffer[2];
+static GGLSurface gr_framebuffer[NUM_BUFFERS];
static GGLSurface gr_mem_surface;
static unsigned gr_active_fb = 0;
static unsigned double_buffering = 0;
+static int overscan_percent = OVERSCAN_PERCENT;
+static int overscan_offset_x = 0;
+static int overscan_offset_y = 0;
static int gr_fb_fd = -1;
static int gr_vt_fd = -1;
@@ -130,6 +134,9 @@ static int get_framebuffer(GGLSurface *fb)
return -1;
}
+ overscan_offset_x = vi.xres * overscan_percent / 100;
+ overscan_offset_y = vi.yres * overscan_percent / 100;
+
fb->version = sizeof(*fb);
fb->width = vi.xres;
fb->height = vi.yres;
@@ -169,7 +176,7 @@ static void get_memory_surface(GGLSurface* ms) {
static void set_active_framebuffer(unsigned n)
{
if (n > 1 || !double_buffering) return;
- vi.yres_virtual = vi.yres * PIXEL_SIZE;
+ vi.yres_virtual = vi.yres * NUM_BUFFERS;
vi.yoffset = n * vi.yres;
vi.bits_per_pixel = PIXEL_SIZE * 8;
if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
@@ -216,15 +223,20 @@ void gr_font_size(int *x, int *y)
*y = gr_font->cheight;
}
-int gr_text(int x, int y, const char *s)
+int gr_text(int x, int y, const char *s, int bold)
{
GGLContext *gl = gr_context;
GRFont *font = gr_font;
unsigned off;
- y -= font->ascent;
+ if (!font->texture) return x;
+
+ bold = bold && (font->texture->height != font->cheight);
- gl->bindTexture(gl, &font->texture);
+ x += overscan_offset_x;
+ y += overscan_offset_y;
+
+ gl->bindTexture(gl, font->texture);
gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
@@ -233,7 +245,8 @@ int gr_text(int x, int y, const char *s)
while((off = *s++)) {
off -= 32;
if (off < 96) {
- gl->texCoord2i(gl, (off * font->cwidth) - x, 0 - y);
+ gl->texCoord2i(gl, (off * font->cwidth) - x,
+ (bold ? font->cheight : 0) - y);
gl->recti(gl, x, y, x + font->cwidth, y + font->cheight);
}
x += font->cwidth;
@@ -242,19 +255,50 @@ int gr_text(int x, int y, const char *s)
return x;
}
-void gr_fill(int x, int y, int w, int h)
+void gr_texticon(int x, int y, gr_surface icon) {
+ if (gr_context == NULL || icon == NULL) {
+ return;
+ }
+ GGLContext* gl = gr_context;
+
+ x += overscan_offset_x;
+ y += overscan_offset_y;
+
+ gl->bindTexture(gl, (GGLSurface*) icon);
+ gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
+ gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+ gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+ gl->enable(gl, GGL_TEXTURE_2D);
+
+ int w = gr_get_width(icon);
+ int h = gr_get_height(icon);
+
+ gl->texCoord2i(gl, -x, -y);
+ gl->recti(gl, x, y, x+gr_get_width(icon), y+gr_get_height(icon));
+}
+
+void gr_fill(int x1, int y1, int x2, int y2)
{
+ x1 += overscan_offset_x;
+ y1 += overscan_offset_y;
+
+ x2 += overscan_offset_x;
+ y2 += overscan_offset_y;
+
GGLContext *gl = gr_context;
gl->disable(gl, GGL_TEXTURE_2D);
- gl->recti(gl, x, y, w, h);
+ gl->recti(gl, x1, y1, x2, y2);
}
void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) {
- if (gr_context == NULL) {
+ if (gr_context == NULL || source == NULL) {
return;
}
GGLContext *gl = gr_context;
+ dx += overscan_offset_x;
+ dy += overscan_offset_y;
+
gl->bindTexture(gl, (GGLSurface*) source);
gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
@@ -280,31 +324,40 @@ unsigned int gr_get_height(gr_surface surface) {
static void gr_init_font(void)
{
- GGLSurface *ftex;
- unsigned char *bits, *rle;
- unsigned char *in, data;
-
gr_font = calloc(sizeof(*gr_font), 1);
- ftex = &gr_font->texture;
- bits = malloc(font.width * font.height);
-
- ftex->version = sizeof(*ftex);
- ftex->width = font.width;
- ftex->height = font.height;
- ftex->stride = font.width;
- ftex->data = (void*) bits;
- ftex->format = GGL_PIXEL_FORMAT_A_8;
+ int res = res_create_surface("font", (void**)&(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->cwidth = gr_font->texture->width / 96;
+ gr_font->cheight = 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 = malloc(sizeof(*gr_font->texture));
+ gr_font->texture->width = font.width;
+ gr_font->texture->height = font.height;
+ gr_font->texture->stride = font.width;
+
+ unsigned char* bits = malloc(font.width * font.height);
+ gr_font->texture->data = (void*) bits;
+
+ unsigned char data;
+ unsigned char* in = font.rundata;
+ while((data = *in++)) {
+ memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
+ bits += (data & 0x7f);
+ }
- in = font.rundata;
- while((data = *in++)) {
- memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
- bits += (data & 0x7f);
+ gr_font->cwidth = font.cwidth;
+ gr_font->cheight = font.cheight;
}
- gr_font->cwidth = font.cwidth;
- gr_font->cheight = font.cheight;
- gr_font->ascent = font.cheight - 2;
+ // interpret the grayscale as alpha
+ gr_font->texture->format = GGL_PIXEL_FORMAT_A_8;
}
int gr_init(void)
@@ -364,12 +417,12 @@ void gr_exit(void)
int gr_fb_width(void)
{
- return gr_framebuffer[0].width;
+ return gr_framebuffer[0].width - 2*overscan_offset_x;
}
int gr_fb_height(void)
{
- return gr_framebuffer[0].height;
+ return gr_framebuffer[0].height - 2*overscan_offset_y;
}
gr_pixel *gr_fb_data(void)
diff --git a/minui/minui.h b/minui/minui.h
index 74da4e9c0..1b8dd059b 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -36,8 +36,9 @@ void gr_flip(void);
void gr_fb_blank(bool blank);
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
-void gr_fill(int x, int y, int w, int h);
-int gr_text(int x, int y, const char *s);
+void gr_fill(int x1, int y1, int x2, int y2);
+int gr_text(int x, int y, const char *s, int bold);
+ void gr_texticon(int x, int y, gr_surface icon);
int gr_measure(const char *s);
void gr_font_size(int *x, int *y);
@@ -71,6 +72,7 @@ void ev_dispatch(void);
// Returns 0 if no error, else negative.
int res_create_surface(const char* name, gr_surface* pSurface);
+int res_create_localized_surface(const char* name, gr_surface* pSurface);
void res_free_surface(gr_surface surface);
#ifdef __cplusplus
diff --git a/minui/resources.c b/minui/resources.c
index 5e2062192..c0a9ccacb 100644
--- a/minui/resources.c
+++ b/minui/resources.c
@@ -33,6 +33,8 @@
#include "minui.h"
+extern char* locale;
+
// libpng gives "undefined reference to 'pow'" errors, and I have no
// idea how to convince the build system to link with -lm. We don't
// need this functionality (it's used for gamma adjustment) so provide
@@ -91,22 +93,25 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
png_set_sig_bytes(png_ptr, sizeof(header));
png_read_info(png_ptr, info_ptr);
- size_t width = info_ptr->width;
- size_t height = info_ptr->height;
- size_t stride = 4 * width;
- size_t pixelSize = stride * height;
+ int color_type, bit_depth;
+ size_t width, height;
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
+ &color_type, NULL, NULL, NULL);
+
+ int channels = png_get_channels(png_ptr, info_ptr);
- int color_type = info_ptr->color_type;
- int bit_depth = info_ptr->bit_depth;
- int channels = info_ptr->channels;
if (!(bit_depth == 8 &&
((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
(channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) ||
- (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) {
+ (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE ||
+ color_type == PNG_COLOR_TYPE_GRAY))))) {
return -7;
goto exit;
}
+ size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width;
+ size_t pixelSize = stride * height;
+
surface = malloc(sizeof(GGLSurface) + pixelSize);
if (surface == NULL) {
result = -8;
@@ -118,8 +123,8 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
surface->height = height;
surface->stride = width; /* Yes, pixels, not bytes */
surface->data = pData;
- surface->format = (channels == 3) ?
- GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888;
+ surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 :
+ ((color_type == PNG_COLOR_TYPE_PALETTE ? GGL_PIXEL_FORMAT_RGBA_8888 : GGL_PIXEL_FORMAT_L_8));
int alpha = 0;
if (color_type == PNG_COLOR_TYPE_PALETTE) {
@@ -129,6 +134,9 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
png_set_tRNS_to_alpha(png_ptr);
alpha = 1;
}
+ if (color_type == PNG_COLOR_TYPE_GRAY) {
+ alpha = 1;
+ }
unsigned int y;
if (channels == 3 || (channels == 1 && !alpha)) {
@@ -173,6 +181,141 @@ exit:
return result;
}
+static int matches_locale(const char* loc) {
+ if (locale == NULL) return 0;
+
+ if (strcmp(loc, locale) == 0) return 1;
+
+ // if loc does *not* have an underscore, and it matches the start
+ // of locale, and the next character in locale *is* an underscore,
+ // that's a match. For instance, loc == "en" matches locale ==
+ // "en_US".
+
+ int i;
+ for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
+ if (loc[i] == '_') return 0;
+
+ return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
+}
+
+int res_create_localized_surface(const char* name, gr_surface* pSurface) {
+ char resPath[256];
+ GGLSurface* surface = NULL;
+ int result = 0;
+ unsigned char header[8];
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+
+ *pSurface = NULL;
+
+ snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
+ resPath[sizeof(resPath)-1] = '\0';
+ FILE* fp = fopen(resPath, "rb");
+ if (fp == NULL) {
+ result = -1;
+ goto exit;
+ }
+
+ size_t bytesRead = fread(header, 1, sizeof(header), fp);
+ if (bytesRead != sizeof(header)) {
+ result = -2;
+ goto exit;
+ }
+
+ if (png_sig_cmp(header, 0, sizeof(header))) {
+ result = -3;
+ goto exit;
+ }
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr) {
+ result = -4;
+ goto exit;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ result = -5;
+ goto exit;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ result = -6;
+ goto exit;
+ }
+
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, sizeof(header));
+ png_read_info(png_ptr, info_ptr);
+
+ int color_type, bit_depth;
+ size_t width, height;
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
+ &color_type, NULL, NULL, NULL);
+ int channels = png_get_channels(png_ptr, info_ptr);
+
+ if (!(bit_depth == 8 &&
+ (channels == 1 && color_type == PNG_COLOR_TYPE_GRAY))) {
+ return -7;
+ goto exit;
+ }
+
+ unsigned char* row = malloc(width);
+ int y;
+ for (y = 0; y < height; ++y) {
+ png_read_row(png_ptr, row, NULL);
+ int w = (row[1] << 8) | row[0];
+ int h = (row[3] << 8) | row[2];
+ int len = row[4];
+ char* loc = row+5;
+
+ if (y+1+h >= height || matches_locale(loc)) {
+ printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
+
+ surface = malloc(sizeof(GGLSurface));
+ if (surface == NULL) {
+ result = -8;
+ goto exit;
+ }
+ unsigned char* pData = malloc(w*h);
+
+ surface->version = sizeof(GGLSurface);
+ surface->width = w;
+ surface->height = h;
+ surface->stride = w; /* Yes, pixels, not bytes */
+ surface->data = pData;
+ surface->format = GGL_PIXEL_FORMAT_A_8;
+
+ int i;
+ for (i = 0; i < h; ++i, ++y) {
+ png_read_row(png_ptr, row, NULL);
+ memcpy(pData + i*w, row, w);
+ }
+
+ *pSurface = (gr_surface) surface;
+ break;
+ } else {
+ int i;
+ for (i = 0; i < h; ++i, ++y) {
+ png_read_row(png_ptr, row, NULL);
+ }
+ }
+ }
+
+exit:
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+ if (fp != NULL) {
+ fclose(fp);
+ }
+ if (result < 0) {
+ if (surface) {
+ free(surface);
+ }
+ }
+ return result;
+}
+
void res_free_surface(gr_surface surface) {
GGLSurface* pSurface = (GGLSurface*) surface;
if (pSurface) {