diff --git a/dcs_lcd_display_driver.c b/dcs_lcd_display_driver.c index 14873ad..3ab2db5 100644 --- a/dcs_lcd_display_driver.c +++ b/dcs_lcd_display_driver.c @@ -156,9 +156,10 @@ static void do_update(Context *ctx, term display_list) bool transaction_in_progress = false; for (int ypos = 0; ypos < screen_height; ypos++) { + BaseDisplayItem *row = display_items_row(items, len, ypos); int xpos = 0; while (xpos < screen_width) { - int drawn_pixels = dcs_lcd_draw_x(&driver->screen, xpos, ypos, items, len); + int drawn_pixels = dcs_lcd_draw_x(&driver->screen, xpos, ypos, row); xpos += drawn_pixels; } diff --git a/dcs_lcd_draw.c b/dcs_lcd_draw.c index 49e888f..32d40f1 100644 --- a/dcs_lcd_draw.c +++ b/dcs_lcd_draw.c @@ -209,16 +209,12 @@ int dcs_lcd_draw_scaled_cropped_img_x(const struct DCSLCDScreen *screen, } int dcs_lcd_draw_x(const struct DCSLCDScreen *screen, - int xpos, int ypos, BaseDisplayItem items[], size_t items_len) + int xpos, int ypos, BaseDisplayItem *row) { int line_len = screen->w - xpos; bool below = false; - for (size_t i = 0; i < items_len; i++) { - BaseDisplayItem *item = &items[i]; - if ((ypos < item->y) || (ypos >= item->y + item->height)) { - continue; - } + for (BaseDisplayItem *item = row; item != NULL; item = item->next) { if (xpos < item->x) { int len_to_item = item->x - xpos; if (len_to_item < line_len) { @@ -233,7 +229,7 @@ int dcs_lcd_draw_x(const struct DCSLCDScreen *screen, int max_line_len = below ? 1 : line_len; int drawn_pixels = 0; - switch (items[i].primitive) { + switch (item->primitive) { case PrimitiveImage: drawn_pixels = dcs_lcd_draw_image_x(screen, xpos, ypos, max_line_len, item); break; diff --git a/dcs_lcd_draw.h b/dcs_lcd_draw.h index 6a79e1d..73c0394 100644 --- a/dcs_lcd_draw.h +++ b/dcs_lcd_draw.h @@ -37,6 +37,6 @@ int dcs_lcd_draw_scaled_cropped_img_x(const struct DCSLCDScreen *screen, int xpos, int ypos, int max_line_len, BaseDisplayItem *item); int dcs_lcd_draw_x(const struct DCSLCDScreen *screen, - int xpos, int ypos, BaseDisplayItem items[], size_t items_len); + int xpos, int ypos, BaseDisplayItem *row); #endif diff --git a/display_items.h b/display_items.h index 50b3168..6fa2260 100644 --- a/display_items.h +++ b/display_items.h @@ -84,6 +84,10 @@ struct BaseDisplayItem int y_scale; bool owns_data; + + // Rendering scratch, never compared: the next item that covers the row being drawn, see + // display_items_row() + struct BaseDisplayItem *next; }; typedef struct BaseDisplayItem BaseDisplayItem; @@ -95,6 +99,23 @@ typedef enum DisplayItemsOutOfMemory } display_items_result_t; +// Links the items that cover row ypos through their next field, in display list order, and +// returns the first of them, or NULL if none does. +static inline BaseDisplayItem *display_items_row(BaseDisplayItem items[], size_t items_len, int ypos) +{ + BaseDisplayItem *head = NULL; + BaseDisplayItem **link = &head; + for (size_t i = 0; i < items_len; i++) { + BaseDisplayItem *item = &items[i]; + if (ypos >= item->y && ypos < item->y + item->height) { + *link = item; + link = &item->next; + } + } + *link = NULL; + return head; +} + void display_items_init_item(BaseDisplayItem *item, term req, Context *ctx); display_items_result_t display_items_new_list(term display_list, BaseDisplayItem **items, size_t *items_len, Context *ctx); diff --git a/epaper_display_driver.c b/epaper_display_driver.c index d719d73..12f9152 100644 --- a/epaper_display_driver.c +++ b/epaper_display_driver.c @@ -215,9 +215,10 @@ static void do_update(Context *ctx, term display_list) spi_device_get_trans_result(driver->bus.spi_disp.handle, &trans, portMAX_DELAY); } + BaseDisplayItem *row = display_items_row(items, len, ypos); int xpos = 0; while (xpos < screen_width) { - int drawn_pixels = epaper_draw_x(&driver->screen, buf, xpos, ypos, items, len); + int drawn_pixels = epaper_draw_x(&driver->screen, buf, xpos, ypos, row); xpos += drawn_pixels; } diff --git a/epaper_draw.c b/epaper_draw.c index c90d2ed..d68013c 100644 --- a/epaper_draw.c +++ b/epaper_draw.c @@ -274,16 +274,12 @@ int epaper_draw_scaled_cropped_img_x(const struct EpaperScreen *screen, int epaper_draw_x(const struct EpaperScreen *screen, uint8_t *line_buf, int xpos, int ypos, - BaseDisplayItem items[], size_t items_len) + BaseDisplayItem *row) { int line_len = screen->w - xpos; bool below = false; - for (size_t i = 0; i < items_len; i++) { - BaseDisplayItem *item = &items[i]; - if ((ypos < item->y) || (ypos >= item->y + item->height)) { - continue; - } + for (BaseDisplayItem *item = row; item != NULL; item = item->next) { if (xpos < item->x) { int len_to_item = item->x - xpos; if (len_to_item < line_len) { @@ -298,7 +294,7 @@ int epaper_draw_x(const struct EpaperScreen *screen, int max_line_len = below ? 1 : line_len; int drawn_pixels = 0; - switch (items[i].primitive) { + switch (item->primitive) { case PrimitiveImage: drawn_pixels = epaper_draw_image_x(screen, line_buf, xpos, ypos, max_line_len, item); break; diff --git a/epaper_draw.h b/epaper_draw.h index 3fb5a28..3f0fe07 100644 --- a/epaper_draw.h +++ b/epaper_draw.h @@ -45,6 +45,6 @@ int epaper_draw_scaled_cropped_img_x(const struct EpaperScreen *screen, int epaper_draw_x(const struct EpaperScreen *screen, uint8_t *line_buf, int xpos, int ypos, - BaseDisplayItem items[], size_t items_len); + BaseDisplayItem *row); #endif diff --git a/memory_display_driver.c b/memory_display_driver.c index 5233fc9..d0b07bd 100644 --- a/memory_display_driver.c +++ b/memory_display_driver.c @@ -118,9 +118,10 @@ static void do_update(Context *ctx, term display_list) memset(buf + 2, 0xFF, DISPLAY_WIDTH / 8); + BaseDisplayItem *row = display_items_row(items, len, ypos); int xpos = 0; while (xpos < screen_width) { - int drawn_pixels = mono_draw_x(&driver->screen, buf + 2, xpos, ypos, items, len); + int drawn_pixels = mono_draw_x(&driver->screen, buf + 2, xpos, ypos, row); xpos += drawn_pixels; } diff --git a/mono_draw.c b/mono_draw.c index 5fa278f..0eaf41d 100644 --- a/mono_draw.c +++ b/mono_draw.c @@ -299,16 +299,12 @@ int mono_draw_scaled_cropped_img_x(const struct MonoScreen *screen, int mono_draw_x(const struct MonoScreen *screen, uint8_t *line_buf, int xpos, int ypos, - BaseDisplayItem items[], size_t items_len) + BaseDisplayItem *row) { int line_len = screen->w - xpos; bool below = false; - for (size_t i = 0; i < items_len; i++) { - BaseDisplayItem *item = &items[i]; - if ((ypos < item->y) || (ypos >= item->y + item->height)) { - continue; - } + for (BaseDisplayItem *item = row; item != NULL; item = item->next) { if (xpos < item->x) { int len_to_item = item->x - xpos; if (len_to_item < line_len) { @@ -323,7 +319,7 @@ int mono_draw_x(const struct MonoScreen *screen, int max_line_len = below ? 1 : line_len; int drawn_pixels = 0; - switch (items[i].primitive) { + switch (item->primitive) { case PrimitiveImage: //fprintf(stderr, "Image\n"); drawn_pixels = mono_draw_image_x(screen, line_buf, xpos, ypos, max_line_len, item); diff --git a/mono_draw.h b/mono_draw.h index 97e0497..e35cd36 100644 --- a/mono_draw.h +++ b/mono_draw.h @@ -50,6 +50,6 @@ int mono_draw_scaled_cropped_img_x(const struct MonoScreen *screen, int mono_draw_x(const struct MonoScreen *screen, uint8_t *line_buf, int xpos, int ypos, - BaseDisplayItem items[], size_t items_len); + BaseDisplayItem *row); #endif diff --git a/oled_display_driver.c b/oled_display_driver.c index 47da592..cd8a3e3 100644 --- a/oled_display_driver.c +++ b/oled_display_driver.c @@ -124,9 +124,10 @@ static void do_update(Context *ctx, term display_list) } for (int ypos = 0; ypos < screen_height; ypos++) { + BaseDisplayItem *row = display_items_row(items, len, ypos); int xpos = 0; while (xpos < screen_width) { - int drawn_pixels = mono_draw_x(&driver->screen, buf, xpos, ypos, items, len); + int drawn_pixels = mono_draw_x(&driver->screen, buf, xpos, ypos, row); xpos += drawn_pixels; } diff --git a/sdl_display/display.c b/sdl_display/display.c index 1313241..5e905b4 100644 --- a/sdl_display/display.c +++ b/sdl_display/display.c @@ -269,16 +269,12 @@ static int draw_text_x(int xpos, int ypos, int max_line_len, BaseDisplayItem *it return drawn_pixels; } -static int draw_x(int xpos, int ypos, BaseDisplayItem items[], size_t items_len) +static int draw_x(int xpos, int ypos, BaseDisplayItem *row) { int line_len = screen->w - xpos; bool below = false; - for (size_t i = 0; i < items_len; i++) { - BaseDisplayItem *item = &items[i]; - if ((ypos < item->y) || (ypos >= item->y + item->height)) { - continue; - } + for (BaseDisplayItem *item = row; item != NULL; item = item->next) { if (xpos < item->x) { int len_to_item = item->x - xpos; if (len_to_item < line_len) { @@ -293,7 +289,7 @@ static int draw_x(int xpos, int ypos, BaseDisplayItem items[], size_t items_len) int max_line_len = below ? 1 : line_len; int drawn_pixels = 0; - switch (items[i].primitive) { + switch (item->primitive) { case PrimitiveImage: drawn_pixels = draw_image_x(xpos, ypos, max_line_len, item); break; @@ -334,9 +330,10 @@ static void do_update(Context *ctx, term display_list) } for (int ypos = 0; ypos < screen->h; ypos++) { + BaseDisplayItem *row = display_items_row(items, len, ypos); int xpos = 0; while (xpos < screen->w) { - xpos += draw_x(xpos, ypos, items, len); + xpos += draw_x(xpos, ypos, row); } } diff --git a/tests/items/test_items.c b/tests/items/test_items.c index b5eaad8..aa369f3 100644 --- a/tests/items/test_items.c +++ b/tests/items/test_items.c @@ -238,10 +238,11 @@ static void render(term display_list, uint16_t *frame) screen.pixels = line; for (int ypos = 0; ypos < SCREEN_H; ypos++) { + BaseDisplayItem *row = display_items_row(items, len, ypos); memset(line, 0, sizeof(line)); int xpos = 0; while (xpos < SCREEN_W) { - int drawn_pixels = dcs_lcd_draw_x(&screen, xpos, ypos, items, len); + int drawn_pixels = dcs_lcd_draw_x(&screen, xpos, ypos, row); if (drawn_pixels <= 0) { fprintf(stderr, "dcs_lcd_draw_x returned %d at (%d, %d)\n", drawn_pixels, xpos, ypos); abort();