Best method to draw a semi-transparent shape

211 views
Skip to first unread message

Malachi Xu

unread,
Jul 4, 2023, 12:44:59 PM7/4/23
to fltk.general
TL;DR: What is the easiest way to draw a semi-transparent shape in FLTK?

I am a beginner in FLTK. Recently, while working with it, I don't seem to find that any of the shape drawing methods (e.g. draw_box(), draw_rect_fill()) provides support for transparent blending.They simply draw an opaque object on the window.

I searched the Internet for some methods to realize this, but IMHO most of them came with flaws. Some of them are:

  1. make a FL_RGB_Image and draw it: https://github.com/fltk-rs/fltk-rs/discussions/987#discussioncomment-1612730;
  2. draw on an FL_Image_Surface and then put it into display: https://groups.google.com/g/fltkgeneral/c/3_cHOA0-IIE/m/zMOTUyO9AgAJ.
They all perform well under small-scale testing. However, when I drew hundreds of shapes at once - the performance dropped so much that it took up to 1 second per redrawing. As a comparison, using draw_box() (without considering transparency), the drawing time is almost unnoticeable. Is there a "smarter" way to draw a semi-transparent rectangle than to build a bunch of Images?

There is also some discussion about how to make the application window transparent, but certainly, that's not what I need.

In case this becomes an X-Y problem...
Let me briefly introduce my goal here.

I'm writing a rich text editor from scratch and dealing with the visual selections. According to the documentation, an Fl_Overlay_Window is used to hold the text content and selection overlay. With pango, the selected ranges have been used to generate several rectangles, each representing an overlay representation of a selected line of text.

So now the problem is how to draw these non-opaque rectangles onto the overlay.

Version & Environment
I am using fltk-rs Rust binding with FLTK 1.4.0. OS is Archlinux running KDE on Wayland.

Albrecht Schlosser

unread,
Jul 4, 2023, 1:16:54 PM7/4/23
to fltkg...@googlegroups.com
On 7/4/23 18:33 Malachi Xu wrote:
> TL;DR: What is the easiest way to draw a semi-transparent shape in FLTK?

Honestly, I don't know. But read on...

> I am a beginner in FLTK. Recently, while working with it, I don't seem
> to find that any of the shape drawing methods (e.g. draw_box(),
> draw_rect_fill()) provides support for transparent blending.They
> simply draw an opaque object on the window.

Yep, that's true. However, there are some (image) drawing methods that
can use alpha blending, as you found out yourself.

> I searched the Internet for some methods to realize this, but IMHO
> most of them came with flaws.
[...]

A new method can be seen in test/cube.cxx which draws a semi-transparent
widget over an OpenGL scene. This is work in progress, and I don't know
if you can utilize the underlying method (already) for normal widget
(rectangle) drawing.

But anyway, here's a pointer (using FLTK 1.4/git):

In test/cube.cxx, line 258, a "color with alpha channel" (75) is defined

```
Fl::set_color(FL_FREE_COLOR, 255, 255, 0, 75);
```

... and assigned to FL_FREE_COLOR which is used to draw the widget's box
in lines 221 and 222, respectively:

```
    Fl_Widget *w = new Fl_Button(10, 10, 120, 30, "FLTK over GL");
    w->color(FL_FREE_COLOR);
```

As I wrote before, this is WIP and I don't know how useful this is or
can be already. Matt wrote this new code and it's very likely that he
may chime in and provide you with more info.

Ian MacArthur

unread,
Jul 4, 2023, 1:21:26 PM7/4/23
to Fltk General
On 4 Jul 2023, at 17:33, Malachi Xu wrote:
>
> TL;DR: What is the easiest way to draw a semi-transparent shape in FLTK?
>
> I am a beginner in FLTK. Recently, while working with it, I don't seem to find that any of the shape drawing methods (e.g. draw_box(), draw_rect_fill()) provides support for transparent blending.They simply draw an opaque object on the window.
>
> I searched the Internet for some methods to realize this, but IMHO most of them came with flaws. Some of them are:
>
> • make a FL_RGB_Image and draw it: https://github.com/fltk-rs/fltk-rs/discussions/987#discussioncomment-1612730;
> • draw on an FL_Image_Surface and then put it into display: https://groups.google.com/g/fltkgeneral/c/3_cHOA0-IIE/m/zMOTUyO9AgAJ.
> They all perform well under small-scale testing. However, when I drew hundreds of shapes at once - the performance dropped so much that it took up to 1 second per redrawing. As a comparison, using draw_box() (without considering transparency), the drawing time is almost unnoticeable. Is there a "smarter" way to draw a semi-transparent rectangle than to build a bunch of Images?

For rendering a complex scene, with transparency and so forth, I’d definitely be looking at GL in an Fl_GL_Window rather than using the fltk base 2D drawing primitives - those were written to support the base widget rendering, really, not as a full-on drawing language.

>
> There is also some discussion about how to make the application window transparent, but certainly, that's not what I need.

No, indeed. That’s a different problem. (Possibly a simpler one, too, with a little bit of platform specific code!)


> In case this becomes an X-Y problem...
> Let me briefly introduce my goal here.
>
> I'm writing a rich text editor from scratch and dealing with the visual selections. According to the documentation, an Fl_Overlay_Window is used to hold the text content and selection overlay.

I don’t think that can be right, is it?
Fl_Overlay_Window seems an unlikely choice for holding the text content...


> With pango, the selected ranges have been used to generate several rectangles, each representing an overlay representation of a selected line of text.
>
> So now the problem is how to draw these non-opaque rectangles onto the overlay.
>
> Version & Environment
> I am using fltk-rs Rust binding with FLTK 1.4.0. OS is Archlinux running KDE on Wayland.

With fltk-rs your best bet may be to see if Mo has any suggestions; most of the fltk devs don’t have that much rust experience, so...



Greg Ercolano

unread,
Jul 4, 2023, 1:47:37 PM7/4/23
to fltkg...@googlegroups.com

On 7/4/23 09:33, Malachi Xu wrote:

TL;DR: What is the easiest way to draw a semi-transparent shape in FLTK?

I am a beginner in FLTK. Recently, while working with it, I don't seem to find that any of the shape drawing methods (e.g. draw_box(), draw_rect_fill()) provides support for transparent blending.They simply draw an opaque object on the window.

I searched the Internet for some methods to realize this, but IMHO most of them came with flaws. Some of them are:

  1. make a FL_RGB_Image and draw it: https://github.com/fltk-rs/fltk-rs/discussions/987#discussioncomment-1612730;
  2. draw on an FL_Image_Surface and then put it into display: https://groups.google.com/g/fltkgeneral/c/3_cHOA0-IIE/m/zMOTUyO9AgAJ.

    I'm pretty sure if you enable cairo support you can access transparency via alpha channels, opacity, etc. It also provides better line drawing by giving you antialiased lines.

    I don't have any examples, and today's a big holiday in the US so I don't have time to poke into this to write an example, but maybe someone else here has some code that demos e.g. drawing overlapping shapes with transparency so you can see how they mix.

 



Albrecht Schlosser

unread,
Jul 4, 2023, 2:14:37 PM7/4/23
to fltkg...@googlegroups.com
On 7/4/23 19:47 Greg Ercolano wrote:
>
>     I'm pretty sure if you enable cairo support you can access
> transparency via alpha channels, opacity, etc. It also provides better
> line drawing by giving you antialiased lines.
>
>     I don't have any examples, and today's a big holiday in the US so
> I don't have time to poke into this to write an example, but maybe
> someone else here has some code that demos e.g. drawing overlapping
> shapes with transparency so you can see how they mix.

Indeed, I have some experimental Cairo based code that shows
overlapping, semi-transparent widgets. It may not be very useful for
"real" code (it uses only simple boxes) but maybe it helps.

The actual Cairo setup used in this example program is based on WIP
("FL/Fl_Cairo2.H") which I intend to contribute to FLTK soon, but one
can also use the existing Cairo support if desired.

See attached example code and screenshot.

No code quality guarantees, use as you like. If you have questions, feel
free to ask here.
cairo_widget.cxx
cairo-transparency.png

Malachi Xu

unread,
Jul 5, 2023, 2:02:55 AM7/5/23
to fltk.general
> For rendering a complex scene, with transparency and so forth, I’d definitely be looking at GL in an Fl_GL_Window rather than using the fltk base 2D drawing primitives - those were written to support the base widget rendering, really, not as a full-on drawing language.
>
> Fl_Overlay_Window seems an unlikely choice for holding the text content...

That is right, but I was supposing that handling the selection overlay is the most "heavy" part of drawing ...... Anyway, I would like to attempt to find a solution one more time before moving to FL_GL_XXX.

> With fltk-rs your best bet may be to see if Mo has any suggestions; most of the fltk devs don’t have that much rust experience, so...

Fortunately fltk-rs is a "pure" language binding for FLTK: in most cases, the codes found in the documentation of FLTK and fltk-rs can be easily translated line by line into the other language's version.

> A new method can be seen in test/cube.cxx which draws a semi-transparent
> widget over an OpenGL scene.

Thanks, I will give it a shot if I switch to OpenGL-based windows.

> I'm pretty sure if you enable cairo support you can access transparency via alpha channels, opacity, etc. It also provides better line drawing by giving you antialiased lines.

> Indeed, I have some experimental Cairo based code that shows
> overlapping, semi-transparent widgets. It may not be very useful for
> "real" code (it uses only simple boxes) but maybe it helps.

Oh yes, Cairo. That is the point I missed before. Will try to implement it with Cairo and come back later to report my results. Thank you all!

Albrecht Schlosser

unread,
Jul 5, 2023, 8:01:33 AM7/5/23
to fltkg...@googlegroups.com
On 7/5/23 04:36 Malachi Xu wrote:
> > A new method can be seen in test/cube.cxx which draws a
> semi-transparent
> > widget over an OpenGL scene.
>
> Thanks, I will give it a shot if I switch to OpenGL-based windows.

Note: What I wanted to say here was: the example in test/cube.cxx
renders transparent FLTK widgets over an OpenGL scene, but I'm not sure
if you can use the same technique to render FLTK widgets in a "normal"
FLTK window. It would be worth a try if you need it, even if you don't
use OpenGL.

OTOH, if you can use Cairo that might be another useful approach...

Ian MacArthur

unread,
Jul 5, 2023, 8:25:30 AM7/5/23
to fltk.general
On Wednesday, 5 July 2023 at 07:02:55 UTC+1 Malachi Xu wrote:
>
> Fl_Overlay_Window seems an unlikely choice for holding the text content...

That is right, but I was supposing that handling the selection overlay is the most "heavy" part of drawing ......

Not really - for text-based rendering, the "heavy" part of the task is often the actual rendering of the anti-aliased text itself. Text rendering is a fairly complex process, with layout, kerning, anti-aliasing etc. to deal with.
So if your core objective is text rendering, I'd expect that to be the "more expensive" part rather than some overlay.

Are you creating your own text handling widgets or are you using the Fl_Text_Editor et al for this?

 
Anyway, I would like to attempt to find a solution one more time before moving to FL_GL_XXX.

If you are creating a text-rendering widget, GL might be the wrong way to go - whilst it handles transparency and so forth efficiently, it's text rendering is not as clever (it is quite low level, in effect you can end up having to draw the character glyphs yourself, which can be a lot of work...)

Cairo has better text handling capabilities (via PanGo etc. usually) so may be the way to go, though Cairo can be slower than GL for some sorts of scenes...

FLTK's own text handling is pretty good (also via PanGo in some cases) so may be all that you need for the basic text string handling an so on.

 

> With fltk-rs your best bet may be to see if Mo has any suggestions; most of the fltk devs don’t have that much rust experience, so...

Fortunately fltk-rs is a "pure" language binding for FLTK: in most cases, the codes found in the documentation of FLTK and fltk-rs can be easily translated line by line into the other language's version.

Though you do need to watch out: for example for the box or frame types - for technical reasons in the porting, Mo has used the name "Frame-types" in the fltk-rs port to refer to what we would call "box-types" in the C++ FLTK code. In C++ FLTK, the "frame-types" are a different (albeit related) thing.
For example, if you use "frame-types" in the C++ code it can produce very strange rendering artefacts, so the "fltk-rs" <-> "fltk" code is not a 1-1 mapping when setting up widget properties as a result.
There are a number of things like that to be aware of...
 

Mo_Al_

unread,
Jul 6, 2023, 8:52:53 AM7/6/23
to fltk.general
I've recently added support for OPTION_CAIROEXT. On the Rust side this requires the cairoext feature flag. And it requires the use of the independent cairo-rs crate to actually use the raw cairo_t pointer from FLTK.

Malachi Xu

unread,
Jul 7, 2023, 2:09:11 AM7/7/23
to fltk.general
Okay, I am back with the results of my latest attempts. The solutions that have been proposed before are mainly:

1 - Specify a color with alpha and draw it (need GL support?)

Schlosser mentioned that

> A new method can be seen in test/cube.cxx which draws a semi-transparent
> widget over an OpenGL scene. This is work in progress, and I don't know
> if you can utilize the underlying method (already) for normal widget
> (rectangle) drawing.

It works even on a normal overlay, with OpenGL support enabled, at least on X11 and Wayland. I have not yet figured out why it still works without an Fl_GL_Window, but... it does seem to. I wrote a short demo in Rust to show that:

```
let app = app::App::default();
let mut overlay_window = OverlayWindow::new(0, 0, 400, 300, "Overlay Window");
overlay_window.draw_overlay(move |_| {
    // This callback is to override the draw_overlay() for overlay_window.
    set_color_with_alpha(Color::Free, 0, 255, 0, 127);
    draw_rect_fill(0, 0, 200, 200, Color::Free);
    set_color_with_alpha(Color::Free, 255, 0, 0, 127);
    draw_rect_fill(100,100, 200, 200, Color::Free);
});
overlay_window.end();
overlay_window.show();
overlay_window.redraw_overlay();
app.run().unwrap();
```

This is quite flat and straightforward so I suppose it is not difficult to translate it into the corresponding C codes ;)

2 - Draw with the underlying Cairo context and primitives

Because Mo has implemented advanced Cairo interface for fltk-rs bindings (thank you!), it is possible to do this now.  See this issue for an example to draw some semi-transparent rectangles.

However, in my particular situation (i.e. drawing shapes onto the overlay of an OverlayWindow), since Fl_X11_Window_Driver only sets the current Cairo context when flush_double()... (at drivers/X11/Fl_X11_Window_Driver.cxx, line 176-179):

```
((Fl_X11_Cairo_Graphics_Driver*)fl_graphics_driver)->set_cairo(cairo_);
// ...
# if defined(FLTK_HAVE_CAIROEXT)
      if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow);
# endif
      draw();
```

... but not when flush_overlay()... (at drivers/X11/Fl_X11_Window_Driver.cxx, line 203-205):

```
((Fl_X11_Cairo_Graphics_Driver*)fl_graphics_driver)->set_cairo(overlay_cairo);
// ...
pWindow->as_overlay_window()->draw_overlay();
```

... so in the draw_overlay() callback, Fl::cairo_cc() will always return the old context, and thus will not draw anything actually. In this case, fl_cairo_gc() exported by X11.H has to be used to get an effective context. I would like to know if this is an intentional behavior or an oversight?

> Are you creating your own text handling widgets or are you using the Fl_Text_Editor et al for this?

I am creating my own widgets without using any text widget provided by FLTK (e.g. Fl_Text_Editor, Fl_Multiline_Input, etc.), because I expect the editor to handle different types of text blocks (plain text, images, code blocks, videos, etc.) and the built-in widgets are obviously too basic for this task. I just use drawing primitives like draw_text(), draw_image() to create new widget and handle events on my own.

> Though you do need to watch out: for example for the box or frame types - for technical reasons in the porting, Mo has used the name "Frame-types" in the fltk-rs port to refer to what we would call "box-types" in the C++ FLTK code. In C++ FLTK, the "frame-types" are a different (albeit related) thing.
> For example, if you use "frame-types" in the C++ code it can produce very strange rendering artefacts, so the "fltk-rs" <-> "fltk" code is not a 1-1 mapping when setting up widget properties as a result.
> There are a number of things like that to be aware of...

I will keep an eye for those. Thanks for the reminder.

Manolo

unread,
Jul 7, 2023, 9:25:39 AM7/7/23
to fltk.general
Le vendredi 7 juillet 2023 à 08:09:11 UTC+2, Malachi Xu a écrit :

It works even on a normal overlay, with OpenGL support enabled, at least on X11 and Wayland. I have not yet figured out why it still works without an Fl_GL_Window, but... it does seem to.


Yes, drawing with transparent colors works with the hybrid Wayland/X11 FLTK library when used both
as a Wayland client or as an X11 client. The reason is because FLTK draws everything with Cairo in these situations
and Cairo knows transparency. The same user code also works under macOS, because FLTK draws using Quartz
that's also modern enough to support transprency. Thus, OpenGL is not necessary in these situations.
Under Windows, FLTK needs OpenGL to draw with transparent colors.

Reply all
Reply to author
Forward
0 new messages