From 6d5f099997587e7153c240808094c6afd3140f8f Mon Sep 17 00:00:00 2001 From: xianjimli Date: Sun, 22 Apr 2018 16:57:05 +0800 Subject: [PATCH] window animator on framebuffer --- SConstruct | 2 +- demos/demo1_app.c | 2 +- demos/res/src/images/slider_drag_p.data | 2 +- src/SConscript | 1 + src/animator/bottom_to_top.inc | 6 +- src/animator/center_scale.inc | 14 ++--- src/animator/common.inc | 40 +++++++++++++ src/animator/fade.inc | 2 +- src/animator/htranslate.inc | 12 ++-- src/animator/top_to_bottom.inc | 13 ++--- src/animator/vtranslate.inc | 12 ++-- src/animator/window_animator_fb.c | 78 +++++++++++++++++++++++++ src/animator/window_animator_nanovg.c | 52 ++--------------- src/base/bitmap.h | 2 +- src/base/canvas.c | 6 +- src/base/canvas.h | 2 +- src/base/dialog.c | 2 +- src/base/layout.c | 2 +- src/base/lcd.c | 9 ++- src/base/lcd.h | 47 ++++++++++++++- src/base/window.c | 1 - src/base/window_animator.c | 2 +- src/base/window_manager.c | 4 +- src/lcd/lcd_mem.inc | 48 +++++++++++++++ src/lcd/lcd_sdl2.c | 12 +++- src/lcd/rgb565.h | 2 + src/lcd/rgba.h | 2 + src/main_loop/main_loop_nanovg.c | 1 - src/main_loop/main_loop_sdl2.c | 3 + tests/canvas_test.cc | 32 +++++----- tests/lcd_mem_test.cc | 2 +- 31 files changed, 304 insertions(+), 111 deletions(-) create mode 100644 src/animator/common.inc create mode 100644 src/animator/window_animator_fb.c diff --git a/SConstruct b/SConstruct index 4dcab5bd0..8898eb5e0 100644 --- a/SConstruct +++ b/SConstruct @@ -10,8 +10,8 @@ GTEST_ROOT = os.path.join(LFTK_ROOT, '3rd/gtest/googletest') BIN_DIR=os.path.join(LFTK_ROOT, 'bin') LIB_DIR=os.path.join(LFTK_ROOT, 'lib') -LCD='SDL' LCD='NANOVG' +LCD='SDL' os.environ['LCD'] = LCD os.environ['BIN_DIR'] = BIN_DIR; diff --git a/demos/demo1_app.c b/demos/demo1_app.c index f11ea43da..a30df6031 100644 --- a/demos/demo1_app.c +++ b/demos/demo1_app.c @@ -115,7 +115,7 @@ ret_t application_init() { progress_bar = progress_bar_create(win, 10, 80, 168, 20); widget_set_value(progress_bar, 40); - timer_add(on_timer, progress_bar, 200); + // timer_add(on_timer, progress_bar, 200); #ifndef WITH_STM32F103ZE_RAW progress_bar_set_show_text(progress_bar, TRUE); diff --git a/demos/res/src/images/slider_drag_p.data b/demos/res/src/images/slider_drag_p.data index b38cb3de5..ef4c1c7b3 100644 --- a/demos/res/src/images/slider_drag_p.data +++ b/demos/res/src/images/slider_drag_p.data @@ -157,4 +157,4 @@ const unsigned char image_slider_drag_p[] = { 0x11,0x96,0xdb,0xc0,0x12,0x96,0xdb,0xff,0x12,0x96,0xdb,0xff,0x12,0x96,0xdb,0xff,0x12,0x96,0xdb,0xff, 0x11,0x96,0xda,0xd0,0x12,0x96,0xda,0xa0,0x10,0x96,0xdc,0x50,0x12,0x96,0xdb,0x00,0x12,0x96,0xdb,0x00, 0x12,0x96,0xdb,0x00,0x12,0x96,0xdb,0x00,0x11,0x95,0xdb,0x00,0x10,0x95,0xda,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x7f,0x00,0x00,};/*3176*/ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};/*3176*/ diff --git a/src/SConscript b/src/SConscript index e5ecf6281..c47354599 100644 --- a/src/SConscript +++ b/src/SConscript @@ -17,6 +17,7 @@ if os.environ['LCD'] == 'NANOVG': sources += ['lcd/lcd_nanovg.c', 'lcd/lcd_mem_rgba.c', 'main_loop/main_loop_nanovg.c']; else: sources += Glob('vgcanvas/vgcanvas_agg.cpp') + sources += ['animator/window_animator_fb.c']; sources += ['lcd/lcd_sdl2.c', 'lcd/lcd_mem_rgba.c', 'main_loop/main_loop_sdl2.c'] env=DefaultEnvironment().Clone() diff --git a/src/animator/bottom_to_top.inc b/src/animator/bottom_to_top.inc index b2202ccd2..12b335e59 100644 --- a/src/animator/bottom_to_top.inc +++ b/src/animator/bottom_to_top.inc @@ -15,7 +15,7 @@ static ret_t window_animator_open_bottom_to_top_draw_prev(window_animator_t* wa) canvas_t* c = wa->canvas; float_t ratio = wa->ratio; widget_t* win = wa->prev_win; - + rect_init(src, win->x * ratio, win->y * ratio, win->w * ratio, win->h * ratio); rect_init(dst, win->x, win->y, win->w, win->h); @@ -39,8 +39,8 @@ static ret_t window_animator_open_bottom_to_top_draw_curr(window_animator_t* wa) #ifdef WITH_NANOVG vgcanvas_t* vg = lcd_get_vgcanvas(c->lcd); vgcanvas_set_global_alpha(vg, alpha); - vgcanvas_draw_image(vg, &(wa->curr_img), win->x * ratio, win->y * ratio, win->w * ratio, h * ratio, - win->x, y, win->w, h); + vgcanvas_draw_image(vg, &(wa->curr_img), win->x * ratio, win->y * ratio, win->w * ratio, + h * ratio, win->x, y, win->w, h); #else rect_init(src, win->x * ratio, win->y * ratio, win->w * ratio, h * ratio); rect_init(dst, win->x, y, win->w, h); diff --git a/src/animator/center_scale.inc b/src/animator/center_scale.inc index cd9ae8207..e32a17078 100644 --- a/src/animator/center_scale.inc +++ b/src/animator/center_scale.inc @@ -15,7 +15,7 @@ static ret_t window_animator_open_scale_draw_prev(window_animator_t* wa) { canvas_t* c = wa->canvas; float_t ratio = wa->ratio; widget_t* win = wa->prev_win; - + rect_init(src, win->x * ratio, win->y * ratio, win->w * ratio, win->h * ratio); rect_init(dst, win->x, win->y, win->w, win->h); @@ -39,17 +39,17 @@ static ret_t window_animator_open_scale_draw_curr(window_animator_t* wa) { rect_init(dst, 0, 0, win->w, win->h); vgcanvas_save(vg); vgcanvas_translate(vg, win->x, win->y); - vgcanvas_translate(vg, win->w>>1, win->h>>1); + vgcanvas_translate(vg, win->w >> 1, win->h >> 1); vgcanvas_scale(vg, scale, scale); - vgcanvas_translate(vg, -win->w>>1, -win->h>>1); + vgcanvas_translate(vg, -win->w >> 1, -win->h >> 1); vgcanvas_set_global_alpha(vg, alpha); vgcanvas_draw_image(vg, &(wa->curr_img), src.x, src.y, src.w, src.h, dst.x, dst.y, dst.w, dst.h); vgcanvas_restore(vg); #else - rect_init(dst, 0, 0, win->w*scale, win->h*scale); - dst.x = win->x + ((win->w-dst.w) >> 1); - dst.y = win->y + ((win->h-dst.h) >> 1); - + rect_init(dst, 0, 0, win->w * scale, win->h * scale); + dst.x = win->x + ((win->w - dst.w) >> 1); + dst.y = win->y + ((win->h - dst.h) >> 1); + log_debug("%d %d %d %d\n", dst.x, dst.y, dst.w, dst.h); lcd_set_global_alpha(c->lcd, alpha * 0xff); lcd_draw_image(c->lcd, &(wa->curr_img), &src, &dst); #endif diff --git a/src/animator/common.inc b/src/animator/common.inc new file mode 100644 index 000000000..5a4f4f3fe --- /dev/null +++ b/src/animator/common.inc @@ -0,0 +1,40 @@ + +static window_animator_t* window_animator_create(window_animator_type_t type, bool_t open) { + window_animator_t* wa = NULL; + + if (type == WINDOW_ANIMATOR_CENTER_SCALE) { + wa = window_animator_create_scale(open); + } else if (type == WINDOW_ANIMATOR_HTRANSLATE) { + wa = window_animator_create_htranslate(open); + } else if (type == WINDOW_ANIMATOR_VTRANSLATE) { + wa = window_animator_create_vtranslate(open); + } else if (type == WINDOW_ANIMATOR_BOTTOM_TO_TOP) { + wa = window_animator_create_bottom_to_top(open); + } else if (type == WINDOW_ANIMATOR_TOP_TO_BOTTOM) { + wa = window_animator_create_top_to_bottom(open); + } else if (type == WINDOW_ANIMATOR_FADE) { + wa = window_animator_create_fade(open); + } + + return wa; +} + +window_animator_t* window_animator_create_for_open(window_animator_type_t type, canvas_t* c, + widget_t* prev_win, widget_t* curr_win) { + window_animator_t* wa = window_animator_create(type, TRUE); + return_value_if_fail(wa != NULL, NULL); + + window_animator_prepare(wa, c, prev_win, curr_win, TRUE); + + return wa; +} + +window_animator_t* window_animator_create_for_close(window_animator_type_t type, canvas_t* c, + widget_t* prev_win, widget_t* curr_win) { + window_animator_t* wa = window_animator_create(type, FALSE); + return_value_if_fail(wa != NULL, NULL); + + window_animator_prepare(wa, c, prev_win, curr_win, FALSE); + + return wa; +} diff --git a/src/animator/fade.inc b/src/animator/fade.inc index e9e203c2e..a29f85202 100644 --- a/src/animator/fade.inc +++ b/src/animator/fade.inc @@ -15,7 +15,7 @@ static ret_t window_animator_open_fade_draw_prev(window_animator_t* wa) { canvas_t* c = wa->canvas; float_t ratio = wa->ratio; widget_t* win = wa->prev_win; - + rect_init(src, win->x * ratio, win->y * ratio, win->w * ratio, win->h * ratio); rect_init(dst, win->x, win->y, win->w, win->h); diff --git a/src/animator/htranslate.inc b/src/animator/htranslate.inc index d4e59bd0a..3ecadc820 100644 --- a/src/animator/htranslate.inc +++ b/src/animator/htranslate.inc @@ -4,7 +4,7 @@ static ret_t window_animator_open_htranslate_update_percent(window_animator_t* w if (wa->open) { wa->percent = percent; } else { - wa->percent = 1.0 - percent; + wa->percent = 1.0 - percent; } return RET_OK; @@ -18,11 +18,12 @@ static ret_t window_animator_open_htranslate_draw_prev(window_animator_t* wa) { widget_t* win = wa->prev_win; float_t percent = wa->percent; float_t x = win->w * percent; - float_t w = win->w * (1-percent); + float_t w = win->w * (1 - percent); #ifdef WITH_NANOVG vgcanvas_t* vg = lcd_get_vgcanvas(c->lcd); - vgcanvas_draw_image(vg, &(wa->prev_img), x * ratio, win->y * ratio, w * ratio, win->h * ratio, 0, win->y, w, win->h); + vgcanvas_draw_image(vg, &(wa->prev_img), x * ratio, win->y * ratio, w * ratio, win->h * ratio, 0, + win->y, w, win->h); #else rect_init(src, x * ratio, win->y * ratio, w * ratio, win->h * ratio); rect_init(dst, 0, win->y, w, win->h); @@ -39,12 +40,13 @@ static ret_t window_animator_open_htranslate_draw_curr(window_animator_t* wa) { float_t ratio = wa->ratio; widget_t* win = wa->curr_win; float_t percent = wa->percent; - float_t x = win->w * (1-percent); + float_t x = win->w * (1 - percent); float_t w = win->w * percent; #ifdef WITH_NANOVG vgcanvas_t* vg = lcd_get_vgcanvas(c->lcd); - vgcanvas_draw_image(vg, &(wa->curr_img), 0, win->y * ratio, w * ratio, win->h * ratio, x, win->y, w, win->h); + vgcanvas_draw_image(vg, &(wa->curr_img), 0, win->y * ratio, w * ratio, win->h * ratio, x, win->y, + w, win->h); #else rect_init(src, 0, win->y * ratio, w * ratio, win->h * ratio); rect_init(dst, x, win->y, w, win->h); diff --git a/src/animator/top_to_bottom.inc b/src/animator/top_to_bottom.inc index 4978cd883..9d785f6c9 100644 --- a/src/animator/top_to_bottom.inc +++ b/src/animator/top_to_bottom.inc @@ -15,7 +15,7 @@ static ret_t window_animator_open_top_to_bottom_draw_prev(window_animator_t* wa) canvas_t* c = wa->canvas; float_t ratio = wa->ratio; widget_t* win = wa->prev_win; - + rect_init(src, win->x * ratio, win->y * ratio, win->w * ratio, win->h * ratio); rect_init(dst, win->x, win->y, win->w, win->h); @@ -32,17 +32,17 @@ static ret_t window_animator_open_top_to_bottom_draw_curr(window_animator_t* wa) widget_t* win = wa->curr_win; float_t percent = wa->percent; float_t h = win->h * percent; - float_t y = win->h * (1-percent); + float_t y = win->h * (1 - percent); float_t alpha = percent; #ifdef WITH_NANOVG vgcanvas_t* vg = lcd_get_vgcanvas(c->lcd); vgcanvas_set_global_alpha(vg, alpha); - vgcanvas_draw_image(vg, &(wa->curr_img), win->x * ratio, y * ratio, win->w * ratio, h * ratio, - win->x, 0, win->w, h); + vgcanvas_draw_image(vg, &(wa->curr_img), win->x * ratio, y * ratio, win->w * ratio, h * ratio, + win->x, 0, win->w, h); #else - rect_init(src, win->x * ratio, win->y * ratio, win->w * ratio, h * ratio); - rect_init(dst, win->x, y, win->w, h); + rect_init(src, win->x * ratio, y * ratio, win->w * ratio, h * ratio); + rect_init(dst, win->x, 0, win->w, h); lcd_set_global_alpha(c->lcd, alpha * 0xff); lcd_draw_image(c->lcd, &(wa->curr_img), &src, &dst); #endif @@ -68,4 +68,3 @@ static window_animator_t* window_animator_create_top_to_bottom(bool_t open) { return wa; } - diff --git a/src/animator/vtranslate.inc b/src/animator/vtranslate.inc index 3178f5616..40e2ebaa3 100644 --- a/src/animator/vtranslate.inc +++ b/src/animator/vtranslate.inc @@ -4,7 +4,7 @@ static ret_t window_animator_open_vtranslate_update_percent(window_animator_t* w if (wa->open) { wa->percent = percent; } else { - wa->percent = 1.0 - percent; + wa->percent = 1.0 - percent; } return RET_OK; @@ -18,11 +18,12 @@ static ret_t window_animator_open_vtranslate_draw_prev(window_animator_t* wa) { widget_t* win = wa->prev_win; float_t percent = wa->percent; float_t y = win->h * percent; - float_t h = win->h * (1-percent); + float_t h = win->h * (1 - percent); #ifdef WITH_NANOVG vgcanvas_t* vg = lcd_get_vgcanvas(c->lcd); - vgcanvas_draw_image(vg, &(wa->prev_img), win->x * ratio, y * ratio, win->w * ratio, h * ratio, win->x, 0, win->w, h); + vgcanvas_draw_image(vg, &(wa->prev_img), win->x * ratio, y * ratio, win->w * ratio, h * ratio, + win->x, 0, win->w, h); #else rect_init(src, win->x * ratio, y * ratio, win->w * ratio, h * ratio); rect_init(dst, win->x, 0, win->w, h); @@ -39,12 +40,13 @@ static ret_t window_animator_open_vtranslate_draw_curr(window_animator_t* wa) { float_t ratio = wa->ratio; widget_t* win = wa->curr_win; float_t percent = wa->percent; - float_t y = win->h * (1-percent); + float_t y = win->h * (1 - percent); float_t h = win->h * percent; #ifdef WITH_NANOVG vgcanvas_t* vg = lcd_get_vgcanvas(c->lcd); - vgcanvas_draw_image(vg, &(wa->curr_img), win->x, 0, win->w * ratio, h * ratio, win->x, y, win->w, h); + vgcanvas_draw_image(vg, &(wa->curr_img), win->x, 0, win->w * ratio, h * ratio, win->x, y, win->w, + h); #else rect_init(src, win->x, 0, win->w * ratio, h * ratio); rect_init(dst, win->x, y, win->w, h); diff --git a/src/animator/window_animator_fb.c b/src/animator/window_animator_fb.c new file mode 100644 index 000000000..2d756c60a --- /dev/null +++ b/src/animator/window_animator_fb.c @@ -0,0 +1,78 @@ +/** + * File: window_animator_fb + * Author: Li XianJing + * Brief: fb implemented window animator + * + * Copyright (c) 2018 - 2018 Li XianJing + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2018-04-22 Li XianJing created + * + */ + +#include "base/mem.h" +#include "base/window_animator.h" + +static ret_t window_animator_open_destroy(window_animator_t* wa) { + bitmap_destroy(&(wa->prev_img)); + bitmap_destroy(&(wa->curr_img)); + + memset(wa, 0x00, sizeof(window_animator_t)); + MEM_FREE(wa); + + return RET_OK; +} + +static ret_t window_animator_close_destroy(window_animator_t* wa) { + widget_destroy(wa->curr_win); + + return window_animator_open_destroy(wa); +} + +static ret_t window_animator_prepare(window_animator_t* wa, canvas_t* c, widget_t* prev_win, + widget_t* curr_win, bool_t open) { + rect_t r; + lcd_t* lcd = c->lcd; + widget_t* wm = prev_win->parent; + + wa->ratio = 1; + wa->canvas = c; + wa->open = open; + wa->duration = 400; + wa->prev_win = prev_win; + wa->curr_win = curr_win; + rect_init(r, 0, 0, wm->w, wm->h); + + ENSURE(canvas_begin_frame(c, &r, LCD_DRAW_OFFLINE) == RET_OK); + ENSURE(widget_paint(prev_win, c) == RET_OK); + ENSURE(lcd_take_snapshot(lcd, &(wa->prev_img)) == RET_OK); + ENSURE(canvas_end_frame(c) == RET_OK); + + ENSURE(canvas_begin_frame(c, &r, LCD_DRAW_OFFLINE) == RET_OK); + ENSURE(widget_paint(curr_win, c) == RET_OK); + ENSURE(lcd_take_snapshot(lcd, &(wa->curr_img)) == RET_OK); + ENSURE(canvas_end_frame(c) == RET_OK); + + wa->prev_img.flags = BITMAP_FLAG_OPAQUE; + wa->curr_img.flags = BITMAP_FLAG_OPAQUE; + + return RET_OK; +} + +#include "fade.inc" +#include "htranslate.inc" +#include "vtranslate.inc" +#include "center_scale.inc" +#include "bottom_to_top.inc" +#include "top_to_bottom.inc" + +#include "common.inc" diff --git a/src/animator/window_animator_nanovg.c b/src/animator/window_animator_nanovg.c index 9db43562e..73296b92b 100644 --- a/src/animator/window_animator_nanovg.c +++ b/src/animator/window_animator_nanovg.c @@ -1,7 +1,7 @@ /** - * File: window_animator_direct + * File: window_animator_nanovg * Author: Li XianJing - * Brief: window_animator_direct + * Brief: nanovg implemented window animator * * Copyright (c) 2018 - 2018 Li XianJing * @@ -34,15 +34,9 @@ static ret_t window_animator_open_destroy(window_animator_t* wa) { } static ret_t window_animator_close_destroy(window_animator_t* wa) { - vgcanvas_t* vg = lcd_get_vgcanvas(wa->canvas->lcd); widget_destroy(wa->curr_win); - vgcanvas_destroy_fbo(vg, &(wa->prev_fbo)); - vgcanvas_destroy_fbo(vg, &(wa->curr_fbo)); - memset(wa, 0x00, sizeof(window_animator_t)); - MEM_FREE(wa); - - return RET_OK; + return window_animator_open_destroy(wa); } static ret_t fbo_to_img(framebuffer_object_t* fbo, bitmap_t* img) { @@ -93,42 +87,4 @@ static ret_t window_animator_prepare(window_animator_t* wa, canvas_t* c, widget_ #include "bottom_to_top.inc" #include "top_to_bottom.inc" -static window_animator_t* window_animator_create(window_animator_type_t type, bool_t open) { - window_animator_t* wa = NULL; - - if(type == WINDOW_ANIMATOR_CENTER_SCALE) { - wa = window_animator_create_scale(open); - } else if(type == WINDOW_ANIMATOR_HTRANSLATE) { - wa = window_animator_create_htranslate(open); - } else if(type == WINDOW_ANIMATOR_VTRANSLATE) { - wa = window_animator_create_vtranslate(open); - } else if(type == WINDOW_ANIMATOR_BOTTOM_TO_TOP) { - wa = window_animator_create_bottom_to_top(open); - } else if(type == WINDOW_ANIMATOR_TOP_TO_BOTTOM) { - wa = window_animator_create_top_to_bottom(open); - } else if(type == WINDOW_ANIMATOR_FADE) { - wa = window_animator_create_fade(open); - } - - return wa; -} - -window_animator_t* window_animator_create_for_open(window_animator_type_t type, canvas_t* c, - widget_t* prev_win, widget_t* curr_win) { - window_animator_t* wa = window_animator_create(type, TRUE); - return_value_if_fail(wa != NULL, NULL); - - window_animator_prepare(wa, c, prev_win, curr_win, TRUE); - - return wa; -} - -window_animator_t* window_animator_create_for_close(window_animator_type_t type, canvas_t* c, - widget_t* prev_win, widget_t* curr_win) { - window_animator_t* wa = window_animator_create(type, FALSE); - return_value_if_fail(wa != NULL, NULL); - - window_animator_prepare(wa, c, prev_win, curr_win, FALSE); - - return wa; -} +#include "common.inc" diff --git a/src/base/bitmap.h b/src/base/bitmap.h index f7a272cdb..62d521309 100644 --- a/src/base/bitmap.h +++ b/src/base/bitmap.h @@ -51,7 +51,7 @@ typedef enum _bitmap_format_t { * @const BITMAP_FMT_RGB565 * 一个像素占用2个字节,RGB分别占用5,6,5位。 */ - BITMAP_FTM_RGB565 + BITMAP_FMT_RGB565 } bitmap_format_t; /** diff --git a/src/base/canvas.c b/src/base/canvas.c index 3f73d5880..8a37c1c2f 100644 --- a/src/base/canvas.c +++ b/src/base/canvas.c @@ -165,14 +165,14 @@ wh_t canvas_measure_text(canvas_t* c, wchar_t* str, int32_t nr) { } } -ret_t canvas_begin_frame(canvas_t* c, rect_t* dirty_rect) { +ret_t canvas_begin_frame(canvas_t* c, rect_t* dirty_rect, lcd_draw_mode_t draw_mode) { return_value_if_fail(c != NULL, RET_BAD_PARAMS); c->ox = 0; c->oy = 0; canvas_set_clip_rect(c, dirty_rect); - return lcd_begin_frame(c->lcd, dirty_rect); + return lcd_begin_frame(c->lcd, dirty_rect, draw_mode); } static ret_t canvas_draw_hline_impl(canvas_t* c, xy_t x, xy_t y, wh_t w) { @@ -863,7 +863,7 @@ ret_t canvas_test_paint(canvas_t* c, bool_t pressed, xy_t x, xy_t y) { color_t bg = color_init(0xff, 0xff, 0, 0xff); color_t fg = color_init(0xff, 0, 0, 0xff); - canvas_begin_frame(c, NULL); + canvas_begin_frame(c, NULL, LCD_DRAW_NORMAL); canvas_set_clip_rect(c, NULL); canvas_set_fill_color(c, bg); canvas_set_stroke_color(c, fg); diff --git a/src/base/canvas.h b/src/base/canvas.h index 2e8741f1e..42d1a9163 100644 --- a/src/base/canvas.h +++ b/src/base/canvas.h @@ -64,7 +64,7 @@ ret_t canvas_set_font(canvas_t* c, const char* name, uint16_t size); wh_t canvas_measure_text(canvas_t* c, wchar_t* str, int32_t nr); -ret_t canvas_begin_frame(canvas_t* c, rect_t* dirty_rect); +ret_t canvas_begin_frame(canvas_t* c, rect_t* dirty_rect, lcd_draw_mode_t draw_mode); ret_t canvas_translate(canvas_t* c, xy_t dx, xy_t dy); ret_t canvas_untranslate(canvas_t* c, xy_t dx, xy_t dy); diff --git a/src/base/dialog.c b/src/base/dialog.c index ceb8e798a..c61c8ea10 100644 --- a/src/base/dialog.c +++ b/src/base/dialog.c @@ -100,7 +100,6 @@ static ret_t dialog_on_relayout_children(widget_t* widget) { return RET_OK; } - static const widget_vtable_t s_dialog_vtable = {.get_prop = dialog_get_prop, .set_prop = dialog_set_prop, .on_layout_children = dialog_on_relayout_children, @@ -145,6 +144,7 @@ widget_t* dialog_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h) { dialog->margin = 0; dialog->title = dialog_title_create(widget, 0, 0, 0, 0); dialog->client = dialog_client_create(widget, 0, 0, 0, 0); + dialog_on_relayout_children(widget); return widget; } diff --git a/src/base/layout.c b/src/base/layout.c index 121666f65..d59e10ee8 100644 --- a/src/base/layout.c +++ b/src/base/layout.c @@ -234,7 +234,7 @@ ret_t widget_layout_children(widget_t* widget) { return RET_OK; } - if(widget->vt->on_layout_children != NULL) { + if (widget->vt->on_layout_children != NULL) { return widget->vt->on_layout_children(widget); } diff --git a/src/base/lcd.c b/src/base/lcd.c index 91b4e83c8..3be770f0b 100644 --- a/src/base/lcd.c +++ b/src/base/lcd.c @@ -21,9 +21,10 @@ #include "base/lcd.h" -ret_t lcd_begin_frame(lcd_t* lcd, rect_t* dirty_rect) { +ret_t lcd_begin_frame(lcd_t* lcd, rect_t* dirty_rect, lcd_draw_mode_t draw_mode) { return_value_if_fail(lcd != NULL && lcd->begin_frame != NULL, RET_BAD_PARAMS); + lcd->draw_mode = draw_mode; return lcd->begin_frame(lcd, dirty_rect); } @@ -183,3 +184,9 @@ vgcanvas_t* lcd_get_vgcanvas(lcd_t* lcd) { return lcd->get_vgcanvas(lcd); } + +ret_t lcd_take_snapshot(lcd_t* lcd, bitmap_t* img) { + return_value_if_fail(lcd != NULL && lcd->take_snapshot != NULL, RET_BAD_PARAMS); + + return lcd->take_snapshot(lcd, img); +} diff --git a/src/base/lcd.h b/src/base/lcd.h index 127b14e94..9f18a12b7 100644 --- a/src/base/lcd.h +++ b/src/base/lcd.h @@ -56,10 +56,36 @@ typedef ret_t (*lcd_draw_text_t)(lcd_t* lcd, wchar_t* str, int32_t nr, xy_t x, x typedef ret_t (*lcd_draw_image_t)(lcd_t* lcd, bitmap_t* img, rect_t* src, rect_t* dst); typedef vgcanvas_t* (*lcd_get_vgcanvas_t)(lcd_t* lcd); +typedef ret_t (*lcd_take_snapshot_t)(lcd_t* lcd, bitmap_t* img); typedef ret_t (*lcd_end_frame_t)(lcd_t* lcd); typedef ret_t (*lcd_destroy_t)(lcd_t* lcd); +/** + * @enum lcd_draw_mode_t + * @prefix LCD_DRAW_ + * LCD绘制模式常量定义。 + */ +typedef enum _lcd_draw_mode_t { + /** + * @const LCD_DRAW_NORMAL + * 正常绘制。 + */ + LCD_DRAW_NORMAL = 0, + /** + * @const LCD_DRAW_ANIMATION + * 绘制动画。 + * 在该模式下,可以直接绘制到显存,不用绘制到framebuffer中。 + */ + LCD_DRAW_ANIMATION, + /** + * @const LCD_DRAW_OFFLINE + * 离线模式绘制(仅适用于framebuffer)。 + * 在该模式下,绘制的内容不会显示出来,但可以用take_snapshot取出来,主要用于窗口动画。 + */ + LCD_DRAW_OFFLINE +} lcd_draw_mode_t; + /** * @class lcd_t * 显示设备抽象基类。 @@ -85,6 +111,7 @@ struct _lcd_t { lcd_get_point_color_t get_point_color; lcd_end_frame_t end_frame; lcd_get_vgcanvas_t get_vgcanvas; + lcd_take_snapshot_t take_snapshot; lcd_destroy_t destroy; @@ -137,6 +164,13 @@ struct _lcd_t { */ uint32_t font_size; + /** + * @property {lcd_draw_mode_t} draw_mode + * @readonly + * 绘制模式。 + */ + lcd_draw_mode_t draw_mode; + rect_t* dirty_rect; }; @@ -145,10 +179,11 @@ struct _lcd_t { * 准备绘制。 * @param {lcd_t*} lcd lcd对象。 * @param {rect_t*} dirty_rect 需要绘制的区域。 + * @param {bool_t} anim_mode 动画模式,如果可能,直接画到显存而不是离线的framebuffer。 * * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 */ -ret_t lcd_begin_frame(lcd_t* lcd, rect_t* dirty_rect); +ret_t lcd_begin_frame(lcd_t* lcd, rect_t* dirty_rect, lcd_draw_mode_t draw_mode); /** * @method lcd_set_clip_rect @@ -350,6 +385,16 @@ ret_t lcd_draw_image(lcd_t* lcd, bitmap_t* img, rect_t* src, rect_t* dst); */ vgcanvas_t* lcd_get_vgcanvas(lcd_t* lcd); +/** + * @method lcd_take_snapshot + * 拍摄快照,一般用于窗口动画,只有framebuffer模式,才支持。 + * @param {lcd_t*} lcd lcd对象。 + * @param {bitmap_t*} img 返回快照图片。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +ret_t lcd_take_snapshot(lcd_t* lcd, bitmap_t* img); + /** * @method lcd_end_frame * 完成绘制,同步到显示设备。 diff --git a/src/base/window.c b/src/base/window.c index 38f12d6a8..abd896a56 100644 --- a/src/base/window.c +++ b/src/base/window.c @@ -87,4 +87,3 @@ ret_t window_close(widget_t* widget) { return window_manager_remove_child(widget->parent, widget); } - diff --git a/src/base/window_animator.c b/src/base/window_animator.c index b72e2b44f..02e68acea 100644 --- a/src/base/window_animator.c +++ b/src/base/window_animator.c @@ -45,7 +45,7 @@ ret_t window_animator_update(window_animator_t* wa, uint32_t time_ms) { } rect_init(r, wm->x, wm->y, wm->w, wm->h); - ENSURE(canvas_begin_frame(c, &r) == RET_OK); + ENSURE(canvas_begin_frame(c, &r, LCD_DRAW_ANIMATION) == RET_OK); if (wa->draw_prev_window != NULL) { wa->draw_prev_window(wa); diff --git a/src/base/window_manager.c b/src/base/window_manager.c index bc7fd23da..8f491b896 100644 --- a/src/base/window_manager.c +++ b/src/base/window_manager.c @@ -152,7 +152,7 @@ ret_t window_manager_remove_child(widget_t* wm, widget_t* window) { return_value_if_fail(wm != NULL && window != NULL, RET_BAD_PARAMS); if (window_manager_check_if_need_close_animation(WINDOW_MANAGER(wm), window) != RET_OK) { - window_manager_remove_child_real(wm, window); + window_manager_remove_child_real(wm, window); idle_add(window_manager_idle_destroy_window, window); } @@ -208,7 +208,7 @@ static ret_t window_manager_paint_normal(widget_t* widget, canvas_t* c) { rect_merge(&r, ldr); if (r.w > 0 && r.h > 0) { - ENSURE(canvas_begin_frame(c, &r) == RET_OK); + ENSURE(canvas_begin_frame(c, &r, LCD_DRAW_NORMAL) == RET_OK); ENSURE(widget_paint(WIDGETP(wm), c) == RET_OK); ENSURE(canvas_end_frame(c) == RET_OK); } diff --git a/src/lcd/lcd_mem.inc b/src/lcd/lcd_mem.inc index 3f5516391..315448410 100644 --- a/src/lcd/lcd_mem.inc +++ b/src/lcd/lcd_mem.inc @@ -19,6 +19,7 @@ * */ +#include "base/mem.h" #include "base/vgcanvas.h" static ret_t lcd_mem_begin_frame(lcd_t* lcd, rect_t* dirty_rect) { @@ -191,6 +192,52 @@ static vgcanvas_t* lcd_mem_get_vgcanvas(lcd_t* lcd) { return mem->vgcanvas; } +static ret_t snapshot_destroy(bitmap_t* img) { + MEM_FREE((void*)(img->data)); + + return RET_OK; +} + +static ret_t lcd_mem_take_snapshot(lcd_t* lcd, bitmap_t* img) { + uint32_t size = 0; + void* data = NULL; + lcd_mem_t* mem = (lcd_mem_t*)lcd; + memset(img, 0x00, sizeof(bitmap_t)); + + img->w = lcd->w; + img->h = lcd->h; + img->format = LCD_FORMAT; + if (img->format == BITMAP_FMT_RGBA) { + uint32_t i = 0; + uint32_t* s = NULL; + uint32_t* d = NULL; + uint32_t nr = img->w * img->h; + size = img->w * img->h * 4; + data = MEM_ALLOC(size); + + return_value_if_fail(data != NULL, RET_FAIL); + + s = (uint32_t*)(mem->pixels); + d = (uint32_t*)data; + + for (i = 0; i < nr; i++, s++, d++) { + uint8_t* ps = (uint8_t*)s; + uint8_t* pd = (uint8_t*)d; + pd[0] = ps[3]; + pd[1] = ps[2]; + pd[2] = ps[1]; + pd[3] = ps[0]; + } + } else { + return_value_if_fail(size > 0, RET_FAIL); + } + + img->destroy = snapshot_destroy; + img->data = (uint8_t*)data; + + return RET_OK; +} + static ret_t lcd_mem_end_frame(lcd_t* lcd) { return RET_OK; } static ret_t lcd_mem_destroy(lcd_t* lcd) { @@ -217,6 +264,7 @@ lcd_t* lcd_mem_create(wh_t w, wh_t h, bool_t alloc) { base->draw_points = lcd_mem_draw_points; base->get_point_color = lcd_mem_get_point_color; base->get_vgcanvas = lcd_mem_get_vgcanvas; + base->take_snapshot = lcd_mem_take_snapshot; base->end_frame = lcd_mem_end_frame; base->destroy = lcd_mem_destroy; diff --git a/src/lcd/lcd_sdl2.c b/src/lcd/lcd_sdl2.c index 0dd99e695..7577acc00 100644 --- a/src/lcd/lcd_sdl2.c +++ b/src/lcd/lcd_sdl2.c @@ -95,7 +95,10 @@ static ret_t lcd_sdl2_end_frame(lcd_t* lcd) { if (dr->w > 0 && dr->h > 0) { SDL_RenderCopy(sdl->render, sdl->texture, NULL, NULL); } - SDL_RenderPresent(sdl->render); + + if (lcd->draw_mode != LCD_DRAW_OFFLINE) { + SDL_RenderPresent(sdl->render); + } return RET_OK; } @@ -107,6 +110,12 @@ static ret_t lcd_sdl2_destroy(lcd_t* lcd) { return RET_OK; } +static ret_t lcd_sdl_take_snapshot(lcd_t* lcd, bitmap_t* img) { + lcd_sdl2_t* mem = (lcd_sdl2_t*)lcd; + + return lcd_take_snapshot((lcd_t*)(mem->lcd_mem), img); +} + static vgcanvas_t* lcd_sdl2_get_vgcanvas(lcd_t* lcd) { lcd_sdl2_t* mem = (lcd_sdl2_t*)lcd; @@ -132,6 +141,7 @@ lcd_t* lcd_sdl2_init(SDL_Renderer* render) { base->draw_points = lcd_sdl2_draw_points; base->end_frame = lcd_sdl2_end_frame; base->get_vgcanvas = lcd_sdl2_get_vgcanvas; + base->take_snapshot = lcd_sdl_take_snapshot; base->destroy = lcd_sdl2_destroy; SDL_GetRendererOutputSize(render, &w, &h); diff --git a/src/lcd/rgb565.h b/src/lcd/rgb565.h index 18731250f..958f1c0a5 100644 --- a/src/lcd/rgb565.h +++ b/src/lcd/rgb565.h @@ -21,6 +21,8 @@ typedef uint16_t pixel_t; +#define LCD_FORMAT BITMAP_FMT_RGB565 + #define rgb_to_pixel(r, g, b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3)) static inline pixel_t to_pixel(color_t c) { return rgb_to_pixel(c.rgba.r, c.rgba.g, c.rgba.b); } diff --git a/src/lcd/rgba.h b/src/lcd/rgba.h index a9c8847f4..bec1ea2e2 100644 --- a/src/lcd/rgba.h +++ b/src/lcd/rgba.h @@ -21,6 +21,8 @@ typedef uint32_t pixel_t; +#define LCD_FORMAT BITMAP_FMT_RGBA + #define rgb_to_pixel(r, g, b) ((r) << 24) | ((g) << 16) | ((b) << 8) | 0xff static inline pixel_t to_pixel(color_t c) { return rgb_to_pixel(c.rgba.r, c.rgba.g, c.rgba.b); } diff --git a/src/main_loop/main_loop_nanovg.c b/src/main_loop/main_loop_nanovg.c index b0ab6afa0..a8f824025 100644 --- a/src/main_loop/main_loop_nanovg.c +++ b/src/main_loop/main_loop_nanovg.c @@ -156,7 +156,6 @@ static ret_t main_loop_nanovg_run(main_loop_t* l) { idle_dispatch(); main_loop_nanovg_paint(loop); - if (!WINDOW_MANAGER(loop->wm)->animating) { SDL_Delay(30); } diff --git a/src/main_loop/main_loop_sdl2.c b/src/main_loop/main_loop_sdl2.c index 193f8afe0..7832df40e 100644 --- a/src/main_loop/main_loop_sdl2.c +++ b/src/main_loop/main_loop_sdl2.c @@ -150,6 +150,9 @@ static ret_t main_loop_sdl2_run(main_loop_t* l) { idle_dispatch(); main_loop_sdl2_paint(loop); + if (!WINDOW_MANAGER(loop->wm)->animating) { + SDL_Delay(30); + } } return RET_OK; diff --git a/tests/canvas_test.cc b/tests/canvas_test.cc index fc416cb6b..2da21e01d 100644 --- a/tests/canvas_test.cc +++ b/tests/canvas_test.cc @@ -15,7 +15,7 @@ TEST(Canvas, draw_hline) { canvas_init(&c, lcd, &font_manager); rect_init(r, 100, 100, 200, 200); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); canvas_draw_hline(&c, 10, 20, 100); @@ -59,7 +59,7 @@ TEST(Canvas, draw_vline) { canvas_init(&c, lcd, &font_manager); rect_init(r, 100, 100, 200, 200); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); canvas_draw_vline(&c, 10, 20, 100); @@ -103,7 +103,7 @@ TEST(Canvas, fill_rect) { canvas_init(&c, lcd, &font_manager); rect_init(r, 100, 100, 200, 200); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); canvas_fill_rect(&c, 10, 10, 10, 10); @@ -187,7 +187,7 @@ TEST(Canvas, draw_points) { points[2].x = x3; \ points[2].y = y3; rect_init(r, 100, 100, 200, 200); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); POINTS3(0, 10, 100, 10, 320, 10); @@ -226,7 +226,7 @@ TEST(Canvas, draw_glyph) { font_manager_add(&font_manager, font_dummy_0("demo0", font_size)); rect_init(r, 100, 100, 200, 200); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); canvas_set_font(&c, "demo0", font_size); lcd_log_reset(lcd); @@ -284,7 +284,7 @@ TEST(Canvas, draw_image) { img.w = 32; img.h = 32; rect_init(r, 100, 100, 200, 200); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(s, 0, 0, img.w, img.h); @@ -356,7 +356,7 @@ TEST(Canvas, draw_image_3patch_x_scale_y) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(d, 0, 0, img.w, img.h); @@ -400,7 +400,7 @@ TEST(Canvas, draw_image_3patch_y_scale_x) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(d, 0, 0, img.w, img.h); @@ -444,7 +444,7 @@ TEST(Canvas, draw_image_9patch) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(d, 0, 0, img.w, img.h); @@ -496,7 +496,7 @@ TEST(Canvas, draw_image_repeat_x) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(r, 0, 0, img.w, img.h); @@ -541,7 +541,7 @@ TEST(Canvas, draw_image_repeat_y) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(r, 0, 0, img.w, img.h); @@ -587,7 +587,7 @@ TEST(Canvas, draw_image_repeat) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(r, 0, 0, img.w, img.h); @@ -634,7 +634,7 @@ TEST(Canvas, draw_image_scale_w) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(r, 0, 0, img.w, img.h); @@ -678,7 +678,7 @@ TEST(Canvas, draw_image_scale_h) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(r, 0, 0, img.w, img.h); @@ -722,7 +722,7 @@ TEST(Canvas, draw_image_scale) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(r, 0, 0, img.w, img.h); @@ -766,7 +766,7 @@ TEST(Canvas, draw_image_center) { img.w = 32; img.h = 32; rect_init(r, 0, 0, 320, 480); - canvas_begin_frame(&c, &r); + canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL); lcd_log_reset(lcd); rect_init(r, 0, 0, img.w, img.h); diff --git a/tests/lcd_mem_test.cc b/tests/lcd_mem_test.cc index e50f36869..4aec65cf0 100644 --- a/tests/lcd_mem_test.cc +++ b/tests/lcd_mem_test.cc @@ -66,7 +66,7 @@ TEST(LCDMem, basic) { canvas_t* c = canvas_init(&canvas, lcd, &font_manager); ASSERT_EQ(c, &canvas); - ASSERT_EQ(canvas_begin_frame(c, NULL), RET_OK); + ASSERT_EQ(canvas_begin_frame(c, NULL, LCD_DRAW_NORMAL), RET_OK); test_draw_points(c); test_fill_rect(c);