News:

Welcome to the Bridgetek Community!

Please read our Welcome Note

Technical Support enquires
please contact the team
@ Bridgetek Support

Please refer to our website for detailed information on all our products - Bridgetek - Bridging Technology

Main Menu

Drawing a circle

Started by Rudolph, October 17, 2026, 05:40:14 PM

Previous topic - Next topic

Rudolph

I am re-visiting my circle function:
void EVE_widget_circle(const int16_t xc0, const int16_t yc0, const uint16_t radius, const uint16_t border, const uint32_t bgcolor)
{
    EVE_save_context();
    EVE_begin(EVE_POINTS);
    EVE_point_size(radius);
    EVE_vertex2f(xc0, yc0);
    EVE_color_rgb(bgcolor);
    EVE_point_size((uint16_t) (radius - border));
    EVE_vertex2f(xc0, yc0);
    EVE_end();
    EVE_restore_context();
}

While that is short and simple, it is a bit odd to use.
The inner area is not transparent, but filled with the provided color.
This is using 9 commands, so 36 bytes in the command-list.

Now I have this:
void EVE_widget_circle(const int16_t xc0, const int16_t yc0, const uint16_t radius, const uint16_t border)
{
    EVE_save_context();
    EVE_color_mask(0, 0, 0, 0);
    EVE_stencil_func(EVE_ALWAYS, 0x01, 0x01);
    EVE_stencil_op(EVE_REPLACE, EVE_REPLACE);
    EVE_point_size((uint16_t) (radius - border));
    EVE_begin(EVE_POINTS);
    EVE_vertex2f(xc0, yc0);
//    EVE_end();
    EVE_color_mask(1, 1, 1, 1);
    EVE_stencil_func(EVE_NOTEQUAL, 0x01, 0x01);
    EVE_stencil_op(EVE_KEEP, EVE_KEEP);
    EVE_point_size(radius);
//    EVE_begin(EVE_POINTS);
    EVE_vertex2f(xc0, yc0);
//    EVE_end();
    EVE_color_mask(0, 0, 0, 0);
    EVE_stencil_func(EVE_ALWAYS, 0x00, 0x01);
    EVE_stencil_op(EVE_REPLACE, EVE_REPLACE);
//    EVE_begin(EVE_POINTS);
    EVE_vertex2f(xc0, yc0);
    EVE_end();
    EVE_restore_context();
}

And this works fine, 18 commands, 72 bytes in the command-list.

At least in the EVE Emulator library I can do this:
EVE_color_rgb(BLACK);
EVE_cmd_text(40, 350, 31, 0, "The quick brown fox jumps...");

EVE_color_rgb(GREEN);
EVE_widget_circle(100,400, 50*16, 8*16);

EVE_color_rgb(RED);
EVE_widget_circle(150,400, 50*16, 8*16);

EVE_color_rgb(MAGENTA);
EVE_widget_circle(220,400, 50*16, 8*16);

I get three overlapping circles and the text underneath.

Hmm, yes, I am also using:
EVE_vertex_format(0);
But neither POINT_SIZE or LINE_WIDTH care about that.

What I am wondering now is, is there a way to do this more efficient?

Edit:
I went with this for a rectangle now:
void EVE_widget_rectangle(const int16_t xc0, const int16_t yc0, const int16_t wid, const int16_t hgt, const uint16_t border)
{
    EVE_save_context();
    EVE_line_width(border);
    EVE_begin(EVE_LINE_STRIP);
    EVE_vertex2f(xc0, yc0);
    EVE_vertex2f(xc0 + wid, yc0);
    EVE_vertex2f(xc0 + wid, yc0 + hgt);
    EVE_vertex2f(xc0, yc0 + hgt);
    EVE_vertex2f(xc0, yc0);
    EVE_end();
    EVE_restore_context();
}


You cannot view this attachment.



pauljiao

Hi Rudolph,

One option worth trying is to clear the stencil while drawing the outer point. Using `EVE_stencil_op(EVE_ZERO, EVE_ZERO)` for that pass should remove the need for the separate cleanup pass:

```c
void EVE_widget_circle(const int16_t xc0, const int16_t yc0,
                       const uint16_t radius, const uint16_t border)
{
    EVE_save_context();
    EVE_stencil_mask(0x01);

    EVE_color_mask(0, 0, 0, 0);
    EVE_stencil_func(EVE_ALWAYS, 0x01, 0x01);
    EVE_stencil_op(EVE_REPLACE, EVE_REPLACE);
    EVE_point_size((uint16_t)(radius - border));
    EVE_begin(EVE_POINTS);
    EVE_vertex2f(xc0, yc0);

    EVE_color_mask(1, 1, 1, 1);
    EVE_stencil_func(EVE_NOTEQUAL, 0x01, 0x01);
    EVE_stencil_op(EVE_ZERO, EVE_ZERO);
    EVE_point_size(radius);
    EVE_vertex2f(xc0, yc0);

    EVE_end();
    EVE_restore_context();
}
```

The inner area fails the stencil test, so its colour remains untouched, but its stencil bit is cleared. The ring passes, draws in the current colour, and also clears the bit.

This gives 15 commands / 60 bytes, including `STENCIL_MASK(0x01)` to preserve the other stencil bits. If that write mask is already configured, it becomes 14 commands / 56 bytes.

This assumes stencil bit 0 is initially clear and available for the widget, and `border <= radius`. `SAVE_CONTEXT`/`RESTORE_CONTEXT` restore the stencil settings, but not the stencil-buffer contents.

Rudolph

Thanks, I tried this and it seems to work at least fine with my test-code in the emulator context.

But, isn't that leaving artifacts in the stencil buffer?
I mean, the general idea is to have this as a universal support.

pauljiao

Pls try on hardware too.   Yes.stencil buffer for the affected pixels will be changed.