LVGL(Light and Versatile Graphics Library)是一个嵌入式图形库,主要用于开发嵌入式人机界面,文档在这里。
现在我们在CodeBlocks中基于SDL2创建一个项目,移植LVGL到SDL2。
1、创建一个SDL2项目(可参考这里)

2、下载LVGL和LVGL示例
1 2 | git clone https://github.com/lvgl/lvgl.git git clone https://github.com/lvgl/lv_examples.git |
clone在项目文件夹内:
(1)复制
(2)复制lv_examples/lv_ex_conf_templ.h到lv_examples同级目录,重命名lv_ex_conf_templ.h为lv_ex_conf_.h;

按照文档添加port部分的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | /*main.c*/ #include <stdio.h> #include <SDL.h> #include "lvgl/lvgl.h" #include "lv_examples/lv_examples.h" SDL_Window *gWin = NULL; SDL_Renderer *gRenderer = NULL; SDL_Texture *gTexture = NULL; static uint32_t tft_buf[LV_HOR_RES_MAX * LV_VER_RES_MAX]; typedef struct InputSDL { bool pressed; lv_coord_t x; lv_coord_t y; } InputSDL_t; InputSDL_t gInput = {false, 0, 0}; static void hal_init(void); static int tick_thread(void *data); static int lvtask_thread(void *data); void my_disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p); void my_disp_flush_ex(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p); void my_set_pixel(int32_t x, int32_t y, lv_color_t *color_p); void my_set_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p); bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data); bool my_touchpad_is_pressed(void); void touchpad_get_xy(lv_coord_t *x, lv_coord_t *y); int main(int argc, char* argv[]){ //1,Call lv_init(). lv_init(); printf("lvgl init ok!\n"); //2,Initialize your drivers. hal_init(); printf("hal init ok!\n"); //3,Register the display and input devices drivers in LittlevGL. /*Static or global buffer(s). The second buffer is optional*/ static lv_disp_buf_t disp_buf; static lv_color_t buf_1[LV_HOR_RES_MAX * 10]; static lv_color_t buf_2[LV_HOR_RES_MAX * 10]; /*Declare a buffer for 10 lines*/ lv_disp_buf_init(&disp_buf, buf_1, buf_2, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/ lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ lv_disp_drv_init(&disp_drv); /*Basic initialization*/ disp_drv.flush_cb = my_disp_flush_ex; /*Set your driver function*/ disp_drv.buffer = &disp_buf; /*Assign the buffer to the display*/ lv_disp_drv_register(&disp_drv); /*Finally register the driver*/ lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); /*Descriptor of a input device driver*/ indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/ indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/ lv_indev_drv_register(&indev_drv); /*Finally register the driver*/ printf("display and input device set ok!\n"); #if LV_USE_DEMO_WIDGETS lv_demo_widgets(); #endif // LV_USE_DEMO_WIDGETS #if LV_USE_DEMO_PRINTER lv_demo_printer(); #endif // LV_USE_DEMO_PRINTER printf("load demo ok!\n"); bool quit = false; SDL_Event e; while(!quit){ while(SDL_PollEvent(&e) != 0){ switch(e.type){ case SDL_QUIT: quit = true; break; case SDL_MOUSEBUTTONDOWN: gInput.pressed = true; gInput.x = e.motion.x; gInput.y = e.motion.y; printf("state= %d, x=%d, y=%d\n", e.button.state, e.motion.x, e.motion.y); break; case SDL_MOUSEBUTTONUP: gInput.pressed = false; printf("state= %d, x=%d, y=%d\n", e.button.state, e.motion.x, e.motion.y); break; case SDL_MOUSEMOTION: gInput.x = e.motion.x; gInput.y = e.motion.y; //printf("mouse motion, x=%d, y=%d\n", e.motion.x, e.motion.y); break; } } } printf("program quit!\n"); SDL_DestroyWindow(gWin); SDL_DestroyRenderer(gRenderer); SDL_Quit(); return 0; } void hal_init(void){ if(SDL_Init(SDL_INIT_VIDEO) != 0){ printf("SDL init failed: %s\n", SDL_GetError()); return; }else{ if(SDL_CreateWindowAndRenderer(LV_HOR_RES_MAX, LV_VER_RES_MAX, SDL_WINDOW_OPENGL, &gWin, &gRenderer) != 0){ printf("SDL create window and renderer failed: %s\n", SDL_GetError()); return; }else{ SDL_SetWindowTitle(gWin, "LittlevGL PC Simulator based on SDL2"); gTexture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, LV_HOR_RES_MAX, LV_VER_RES_MAX); SDL_SetRenderDrawColor(gRenderer, 0xff, 0xff, 0xff, 0xff); SDL_RenderClear(gRenderer); SDL_RenderCopy(gRenderer, gTexture, NULL, NULL); SDL_RenderPresent(gRenderer); } } SDL_CreateThread(tick_thread, "tick", NULL); printf("create tick thread ok!\n"); SDL_CreateThread(lvtask_thread, "lvtask", NULL); printf("create lvtask thread ok!\n"); } static int tick_thread(void *data) { while(1) { lv_tick_inc(10); SDL_Delay(10); /*Sleep for 1 millisecond*/ } return 0; } static int lvtask_thread(void *data){ while(1){ lv_task_handler(); SDL_Delay(5); } } void my_disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p){ int32_t x, y; for(y = area->y1; y <= area->y2; y++) { for(x = area->x1; x <= area->x2; x++) { my_set_pixel(x, y, color_p); /* Put a pixel to the display.*/ color_p++; } } SDL_RenderPresent(gRenderer); lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/ } void my_disp_flush_ex(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p){ int32_t x1 = area->x1; int32_t x2 = area->x2; int32_t y1 = area->y1; int32_t y2 = area->y2; if(x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0 || x1 > LV_HOR_RES_MAX - 1 || x2 > LV_HOR_RES_MAX - 1 || y1 > LV_VER_RES_MAX - 1 || y2 > LV_VER_RES_MAX - 1){ lv_disp_flush_ready(disp); return; } uint32_t w = x2 - x1 + 1; for(int32_t y = y1; y <= y2; y++) { memcpy(&tft_buf[y * LV_HOR_RES_MAX + x1], color_p, w * sizeof(lv_color_t)); color_p += w; } SDL_UpdateTexture(gTexture, NULL, tft_buf, LV_HOR_RES_MAX * sizeof(uint32_t)); SDL_RenderClear(gRenderer); SDL_RenderCopy(gRenderer, gTexture, NULL, NULL); SDL_RenderPresent(gRenderer); lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/ } void my_set_pixel(int32_t x, int32_t y, lv_color_t *color_p){ SDL_SetRenderDrawColor(gRenderer, color_p->ch.red, color_p->ch.green, color_p->ch.blue, color_p->ch.alpha); SDL_RenderDrawPoint(gRenderer, x, y); } bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) { data->state = my_touchpad_is_pressed() ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; if(data->state == LV_INDEV_STATE_PR) touchpad_get_xy(&data->point.x, &data->point.y); return false; /*Return `false` because we are not buffering and no more data to read*/ } bool my_touchpad_is_pressed(void){ return gInput.pressed; } void touchpad_get_xy(lv_coord_t *x, lv_coord_t *y){ *x = gInput.x; *y = gInput.y; } |
3、编译、运行:

项目地址:点击这里