Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions components/flow3r_bsp/flow3r_bsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, int scale,
void *osd_data, int osd_x0, int osd_y0,
int osd_x1, int osd_y1);

// Send pre-rendered pixel data to a rectangular region of the display.
// Data is w*h pixels of 16bpp RGB565 byteswapped, contiguous row-major.
void flow3r_bsp_display_send_rect(const void *data,
uint16_t x, uint16_t y,
uint16_t w, uint16_t h);

// Set display backlight, as integer percent value (from 0 to 100, clamped).
// No-op if display hasn't been successfully initialized.
void flow3r_bsp_display_set_backlight(uint8_t percent);
Expand Down
10 changes: 10 additions & 0 deletions components/flow3r_bsp/flow3r_bsp_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ void flow3r_bsp_display_send_fb(void *fb_data, int bits) {
flow3r_bsp_display_send_fb_osd(fb_data, bits, 1, NULL, 0, 0, 0, 0);
}

void flow3r_bsp_display_send_rect(const void *data,
uint16_t x, uint16_t y,
uint16_t w, uint16_t h) {
if (!gc9a01_initialized) return;
esp_err_t ret = flow3r_bsp_gc9a01_blit_rect(&gc9a01, data, x, y, w, h);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "display rect blit failed: %s", esp_err_to_name(ret));
}
}

void flow3r_bsp_display_set_backlight(uint8_t percent) {
if (!gc9a01_initialized) {
return;
Expand Down
20 changes: 20 additions & 0 deletions components/flow3r_bsp/flow3r_bsp_gc9a01.c
Original file line number Diff line number Diff line change
Expand Up @@ -1096,3 +1096,23 @@ esp_err_t flow3r_bsp_gc9a01_blit_full(flow3r_bsp_gc9a01_t *gc9a01,
const void *fb, int bits) {
return flow3r_bsp_gc9a01_blit_osd(gc9a01, fb, bits, 1, NULL, 0, 0, 0, 0);
}

esp_err_t flow3r_bsp_gc9a01_blit_rect(flow3r_bsp_gc9a01_t *gc9a01,
const void *data,
uint16_t x, uint16_t y,
uint16_t w, uint16_t h) {
if (x >= 240 || y >= 240 || w == 0 || h == 0) return ESP_OK;
if (x + w > 240) w = 240 - x;
if (y + h > 240) h = 240 - y;

esp_err_t ret;
ret = flow3r_bsp_gc9a01_column_set(gc9a01, x, x + w - 1);
if (ret != ESP_OK) return ret;
ret = flow3r_bsp_gc9a01_row_set(gc9a01, y, y + h - 1);
if (ret != ESP_OK) return ret;
ret = flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_RAMWR);
if (ret != ESP_OK) return ret;
ret = flow3r_bsp_gc9a01_data_sync(gc9a01, data, w * h * 2);

return ret;
}
9 changes: 9 additions & 0 deletions components/flow3r_bsp/flow3r_bsp_gc9a01.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ esp_err_t flow3r_bsp_gc9a01_blit_osd(flow3r_bsp_gc9a01_t *gc9a01,
const void *osd_fb, int osd_x0, int osd_y0,
int osd_x1, int osd_y1);

// Send pre-rendered pixel data to a rectangular region of the display.
// Data must be w*h pixels in 16bpp RGB565 byteswapped format, packed
// contiguously (row-major, no stride gaps).
// Coordinates are clamped to display bounds.
esp_err_t flow3r_bsp_gc9a01_blit_rect(flow3r_bsp_gc9a01_t *gc9a01,
const void *data,
uint16_t x, uint16_t y,
uint16_t w, uint16_t h);

// Set backlight for display, using integer percent value (0-100, clamped).
esp_err_t flow3r_bsp_gc9a01_backlight_set(flow3r_bsp_gc9a01_t *gc9a01,
uint8_t value);
100 changes: 75 additions & 25 deletions drivers/gc9a01/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,38 +30,62 @@ static MP_DEFINE_CONST_FUN_OBJ_0(get_fps_obj, get_fps);
#define TILDAGON_DISPLAY_WIDTH 240
#define TILDAGON_DISPLAY_HEIGHT 240

//EXT_RAM_BSS_ATTR
static uint8_t tildagon_fb[TILDAGON_DISPLAY_WIDTH * TILDAGON_DISPLAY_HEIGHT * 2];
static Ctx *tildagon_ctx = NULL;

// #define TILDAGON_CTX_CB_MODE

#ifdef TILDAGON_CTX_CB_MODE

#define TILDAGON_SCRATCH_ROWS 32

// EXT_RAM_BSS_ATTR
static uint8_t tildagon_scratch[TILDAGON_DISPLAY_WIDTH * TILDAGON_SCRATCH_ROWS * 2];

static void tildagon_set_pixels(Ctx *ctx, void *user_data,
int x, int y, int w, int h, void *buf) {
flow3r_bsp_display_send_rect(buf, x, y, w, h);
}

Ctx *tildagon_gfx_ctx(void)
{
if (tildagon_ctx == NULL)
{
tildagon_ctx = ctx_new_for_framebuffer (tildagon_fb, TILDAGON_DISPLAY_WIDTH, TILDAGON_DISPLAY_HEIGHT, TILDAGON_DISPLAY_WIDTH * 2, CTX_FORMAT_RGB565_BYTESWAPPED);
tildagon_ctx = ctx_new_cb(TILDAGON_DISPLAY_WIDTH, TILDAGON_DISPLAY_HEIGHT,
CTX_FORMAT_RGB565_BYTESWAPPED,
tildagon_set_pixels, NULL,
NULL, NULL,
sizeof(tildagon_scratch),
tildagon_scratch,
CTX_FLAG_HASH_CACHE);
}
return tildagon_ctx;
}

void tildagon_start_frame(Ctx *ctx)
void tildagon_end_frame(Ctx *ctx)
{
int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2;
int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2;

ctx_save (ctx);
ctx_identity (ctx);
ctx_apply_transform (ctx, 1.0f, 0.0f, offset_x, 0.0f, 1.0f, offset_y, 0.0f, 0.0f, 1.0f);
ctx_restore (ctx);
ctx_end_frame (ctx);
st3m_gfx_fps_update ();
}

static mp_obj_t get_ctx() {
Ctx *ctx = tildagon_gfx_ctx();
assert (ctx);
tildagon_start_frame (ctx);
return mp_ctx_from_ctx(ctx);
#else /* framebuffer mode */

// EXT_RAM_BSS_ATTR
static uint8_t tildagon_fb[TILDAGON_DISPLAY_WIDTH * TILDAGON_DISPLAY_HEIGHT * 2];

Ctx *tildagon_gfx_ctx(void)
{
if (tildagon_ctx == NULL)
{
tildagon_ctx = ctx_new_for_framebuffer(tildagon_fb,
TILDAGON_DISPLAY_WIDTH, TILDAGON_DISPLAY_HEIGHT,
TILDAGON_DISPLAY_WIDTH * 2,
CTX_FORMAT_RGB565_BYTESWAPPED);
}
return tildagon_ctx;
}
static MP_DEFINE_CONST_FUN_OBJ_0(get_ctx_obj, get_ctx);

void tildagon_blit_fb (void)
static void tildagon_blit_fb(void)
{
flow3r_bsp_display_send_fb(tildagon_fb, 16);
}
Expand All @@ -77,6 +101,32 @@ void tildagon_end_frame(Ctx *ctx)
st3m_gfx_fps_update ();
}

#endif /* TILDAGON_CTX_CB_MODE */

void tildagon_start_frame(Ctx *ctx)
{
int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2;
int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2;

ctx_save (ctx);
#ifndef TILDAGON_CTX_CB_MODE
// In framebuffer mode, identity resets any leftover state since
// ctx_end_frame() is never called. In cb mode ctx_end_frame() resets
// the state and the identity would override the tile offset that the
// cb backend applies via ctx_translate before replaying the drawlist.
ctx_identity (ctx);
#endif
ctx_apply_transform (ctx, 1.0f, 0.0f, offset_x, 0.0f, 1.0f, offset_y, 0.0f, 0.0f, 1.0f);
}

static mp_obj_t get_ctx() {
Ctx *ctx = tildagon_gfx_ctx();
assert (ctx);
tildagon_start_frame (ctx);
return mp_ctx_from_ctx(ctx);
}
static MP_DEFINE_CONST_FUN_OBJ_0(get_ctx_obj, get_ctx);

static mp_obj_t end_frame(mp_obj_t ctx) {
mp_ctx_obj_t *self = MP_OBJ_TO_PTR(ctx);
tildagon_end_frame (self->ctx);
Expand All @@ -98,36 +148,36 @@ static mp_obj_t hexagon(size_t n_args, const mp_obj_t *args) {
float x = mp_obj_get_float(args[1]);
float y = mp_obj_get_float(args[2]);
float dim = mp_obj_get_float(args[3]);

// All the internal angles are 120 degrees, or 2/3 pi radians
// This translates to either an offset of (1, 0) or the pair below
float minor_component = cos(M_PI / 3);
float major_component = sin(M_PI / 3);

// Stash the caller's axes
ctx_save(ctx->ctx);

// Set the origin to the centre of the hexagon and scale to the size
ctx_translate (ctx->ctx, x, y);
ctx_scale (ctx->ctx, dim, dim);

// Rotate so point is at the top - the drawing code has the flat side at the top
ctx_rotate(ctx->ctx, M_PI / 2.0f);

// Move to the start of the top left line
ctx_move_to(ctx->ctx, -minor_component, -major_component);

// Draw the six segments
ctx_rel_line_to(ctx->ctx, 1.0f, 0.0f);
ctx_rel_line_to(ctx->ctx, minor_component, major_component);
ctx_rel_line_to(ctx->ctx, -minor_component, major_component);
ctx_rel_line_to(ctx->ctx, -1.0f, 0.0f);
ctx_rel_line_to(ctx->ctx, -minor_component, -major_component);
ctx_rel_line_to(ctx->ctx, minor_component, -major_component);

// Fill the hexagon
ctx_fill(ctx->ctx);

// Restore the axes
ctx_restore(ctx->ctx);

Expand Down
Loading