From 12cd43b47db4460a508a6e62d53adc84698bdcaa Mon Sep 17 00:00:00 2001
From: Michael Gebhard <m.gebhard.91@gmail.com>
Date: Fri, 23 Aug 2019 14:07:17 +0200
Subject: [PATCH] display: add set_all function

Draw an entire image on the display, to achieve
better framerates when playing videos.
---
 epicardium/epicardium.h         |  2 ++
 epicardium/modules/display.c    | 11 +++++++++++
 lib/gfx/gfx.c                   | 15 +++++++++++++++
 lib/gfx/gfx.h                   |  1 +
 pycardium/modules/py/display.py | 11 +++++++++++
 pycardium/modules/sys_display.c | 23 +++++++++++++++++++++++
 6 files changed, 63 insertions(+)

diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 08f5ff97..e7947439 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -54,6 +54,7 @@ typedef _Bool bool;
 #define API_DISP_PIXEL             0x28
 #define API_DISP_FRAMEBUFFER       0x29
 #define API_DISP_BACKLIGHT         0x2a
+#define API_DISP_SET_ALL           0x2b
 
 /* API_BATTERY_VOLTAGE              0x30 */
 #define API_BATTERY_CURRENT        0x31
@@ -1336,6 +1337,7 @@ API(API_DISP_CIRC,
  */
 API(API_DISP_FRAMEBUFFER, int epic_disp_framebuffer(union disp_framebuffer *fb));
 
+API(API_DISP_SET_ALL, int epic_disp_set_all(int32_t w, int32_t h, uint8_t *color));
 
 /**
  * Set the backlight brightness value
diff --git a/epicardium/modules/display.c b/epicardium/modules/display.c
index c8dc5149..0fc402fc 100644
--- a/epicardium/modules/display.c
+++ b/epicardium/modules/display.c
@@ -48,6 +48,17 @@ int epic_disp_clear(uint16_t color)
 	}
 }
 
+int epic_disp_set_all(int32_t w, int32_t h, uint8_t *color)
+{
+	int cl = check_lock();
+	if (cl < 0) {
+		return cl;
+	} else {
+		gfx_set_all(&display_screen, w, h, color);
+		return 0;
+	}
+}
+
 int epic_disp_pixel(uint16_t x, uint16_t y, uint16_t color)
 {
 	int cl = check_lock();
diff --git a/lib/gfx/gfx.c b/lib/gfx/gfx.c
index 55f1debf..143ccd83 100644
--- a/lib/gfx/gfx.c
+++ b/lib/gfx/gfx.c
@@ -13,6 +13,21 @@ const struct gfx_color_rgb gfx_colors_rgb[COLORS] = {
 	{ 255, 255, 0 }    /* YELLOW */
 };
 
+void gfx_set_all(struct gfx_region *r, int32_t w, int32_t h, uint8_t *color)
+{
+	for (int32_t i = 0; i < w*h; i++) {
+		fb_setpixel(r->fb,
+			(i%w),
+			(i/w),
+			fb_encode_color_rgb(r->fb,
+				color[(3*i)+0],
+				color[(3*i)+1],
+				color[(3*i)+2]
+			));
+	}
+	r->fb->update(r->fb);
+}
+
 void gfx_setpixel(struct gfx_region *r, int x, int y, Color c)
 {
 	if (x < 0 || y < 0)
diff --git a/lib/gfx/gfx.h b/lib/gfx/gfx.h
index 428b196c..7fee0608 100644
--- a/lib/gfx/gfx.h
+++ b/lib/gfx/gfx.h
@@ -12,6 +12,7 @@ struct gfx_region {
 	size_t height;
 };
 
+void gfx_set_all(struct gfx_region *r, int32_t w, int32_t h, uint8_t *color);
 void gfx_setpixel(struct gfx_region *r, int x, int y, Color c);
 struct gfx_region gfx_screen(struct framebuffer *fb);
 void gfx_putchar(sFONT *font, struct gfx_region *reg, int x, int y, char ch,
diff --git a/pycardium/modules/py/display.py b/pycardium/modules/py/display.py
index e957977d..df1c7a61 100644
--- a/pycardium/modules/py/display.py
+++ b/pycardium/modules/py/display.py
@@ -101,6 +101,17 @@ class Display:
         sys_display.backlight(brightness)
         return self
 
+    def set_all(self, w, h, colors):
+        """
+        Draw entire image on the display
+
+        :param w: width, 0 < w <= 160
+        :param h: height, 0 < h <= 80
+        :param colors: w*h*3 RGB values
+        """
+        sys_display.set_all(w, h, colors)
+        return self
+
     def line(self, xs, ys, xe, ye, *, col=None, dotted=False, size=1):
         """
         Draws a line on the display.
diff --git a/pycardium/modules/sys_display.c b/pycardium/modules/sys_display.c
index f5523d54..e3470b9d 100644
--- a/pycardium/modules/sys_display.c
+++ b/pycardium/modules/sys_display.c
@@ -53,6 +53,28 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
 	display_print_obj, 5, 5, mp_display_print
 );
 
+static mp_obj_t mp_display_set_all(mp_obj_t w_in, mp_obj_t h_in, mp_obj_t color_in)
+{
+	uint32_t len = mp_obj_get_int(mp_obj_len(color_in));
+	uint32_t w = mp_obj_get_int(w_in);
+	uint32_t h = mp_obj_get_int(h_in);
+	if (w*h*3 != len) {
+		mp_raise_ValueError("width * height * 3 does not match frame size");
+	}
+	uint8_t pattern[len];
+	for (int32_t i = 0; i < len; i++) {
+		pattern[i] = mp_obj_get_int(mp_obj_subscr(
+			color_in, mp_obj_new_int(i), MP_OBJ_SENTINEL)
+		);
+	}
+	int res = epic_disp_set_all(w, h, (uint8_t *)pattern);
+	if (res < 0) {
+		mp_raise_OSError(-res);
+	}
+	return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_3(display_set_all_obj, mp_display_set_all);
+
 /* draw pixel on the display */
 static mp_obj_t mp_display_pixel(size_t n_args, const mp_obj_t *args)
 {
@@ -236,6 +258,7 @@ static const mp_rom_map_elem_t display_module_globals_table[] = {
 	{ MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&display_print_obj) },
 	{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&display_pixel_obj) },
 	{ MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&display_backlight_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_set_all), MP_ROM_PTR(&display_set_all_obj) },
 	{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&display_line_obj) },
 	{ MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&display_rect_obj) },
 	{ MP_ROM_QSTR(MP_QSTR_circ), MP_ROM_PTR(&display_circ_obj) },
-- 
GitLab