clipping JGraphics layers to non rectangular regions

Luigi Castelli's icon

When writing UI objects I love layers. I use them all the time. They make drawing so much more efficient while preserving the beauty of vectorized graphic (they start to pixelate only at really high zoom ratios) However there's one thing I just cannot do with layers that bothers me, and that is clipping the graphic context. For instance, the look of Max 6 is all about rounded corners all over the place, right? Well, in a complex UI object an obvious strategy would be to do all the drawing in a layer and then clip the layer itself to those nice and smooth rounded corners, but with JGraphics that doesn't seem to be possible. Sure, I could draw into a jsurface and then clip that but then I would lose all the benefits of vector graphics because surfaces are like bitmap images and as soon as zoomed they will pixelate.

So, to summarize I would like to achieve the following:
1 - For efficiency, use layers' validation/invalidation scheme to allow graphics to be redrawn only when its content changes.
2 - Keep the nice properties of antialiased vector graphics which will allow the graphics to be zoomed in and out without incurring in pixelation artifacts.
3 - Be able to clip layers or graphic context to a shape other than rectangular.

In Max 6 with the JGraphics API is it possible to achieve all of the above?

- Luigi

danieleghisi's icon

Definitely +1 for achieving such clipping!

Rob Sussman's icon

The way to clip your drawing to a non-rectangular region is to use an offscreen to fill a path.

The jgraphics boxlayer stuff is mostly just a convenient way to create and manage offscreen surfaces. However, it doesn't let you control how the layer is painted to the box. To do what you want you will probably need to create your own surface via jgraphics_image_surface_create().

Once you have your offscreen surface, you can use jgraphics_set_source_surface() to set the surface as the current "pattern" for filling.

Then you can establish the path that you want your drawing to be "clipped" by. For example, you could call jgraphics_ellipse(). And finally, jgraphics_fill() will then fill the path with the current pattern (set to your surface above).

Hope that helps,
Rob

Luigi Castelli's icon

Yes, this method works, however it pixelates as soon as the patcher zoom ratio is set to something bigger than 100%. That's because a surface is like a bitmap image. The great feature of layers is that they keep the nice properties of antialiased vector graphics, so that they can be zoomed in and won't incur in any pixelation artifacts. You could implement a mechanism to overcome that in the method that Rob suggested by using the patcherview "zoomratio" attribute and by scaling the graphic commands to the surface. However the whole mechanism gets very convoluted very fast and performance degrades noticeably. I'd much rather have control on how layers are painted to the box.

Luigi