I have added a component with the same background colour like the plugin background and used setOpaque(true) because the component changes it’s colours and i want to suppress the re-rendering of the whole UI. This works if i don’t scale the UI. If i scale the UI, i can see a small border around the component:
I understand that this happens because the overlaying component does not blend colours with setOpaque(true) enabled and because the scaling does not hit exactly the pixels.
Is there a way to avoid this issue. Maybe something like snap to pixels or a totally different solution?
Just a shot in the dark, your issue might be something else, but is this on osx with the openGL renderer?
Does the component use an image, or are you painting it?
With opengl and images, you might need that to avoid glitches : #define JUCE_OPENGL_ALLOW_NON_POWER_OF_TWO_TEXTURES (1)
Thanks for the fast reply. I do not use OpenGL and there are no images involved. I’m using fillAll() to paint the background of the plugin and the component. It happens only if i scale the UI with an affine transform.
Thanks for pointing to that. It looks that this isn’t related. I get the issue also when i draw a very bold border. It seems that it is something that can’t be changed within the paint method. Something on the component borders. And it looks like empty opaque components always are white.
The problem could be solved if there is a way how i can change the default opaque color to the background color.
No, that didn’t help. I believe @daniel pointed to the right direction. It seems that the graphic context does not fit the component bounds when scaling with affine transform. I think it’s a float / int issue.
The reason is actually quite complicated and subtle though… Yes, partly float/int rounding, but even if all coordinates and clipping was completely floating point, then the way that graphics engines perform sub-pixel anti-aliasing will still cause artefacts if you draw two adjacent rectangles - if you imagine splitting a pixel halfway, so each half is drawn with an alpha of 0.5, and then you alpha-composite two 0.5-level pixels, then the result is actually 0.75 rather than 1.0, so is lighter. It’s just a side-effect of the maths, and the only way to avoid it is for an engine to render using no anti-aliasing at a much higher resolution, and then down-sample the result.
You’ll get the same visual artifacts if you’re rendering a bitmap that is within a scaled component.
We routinely have the problem that bitmaps have these extra “garbage” pixels on the right and bottom and ONLY if we attach an OpenGL context to speed up the UI rendering. If we don’t attach the context, the problem disappears.
Another work-around we found is making the source bitmap about 1.5x larger than the target resolution. At least then it’s less visible with our bitmaps and colors.
Could it be that in this particular case the Component is bitmap-cached?
A simple fix would be to just not make the child opaque, and let the parent fill the background. If the parent’s paint method is slow, then add logic to it so it avoids wasting time calculating or trying to paint the occluded areas.
But really, like I said above, unless the rasteriser uses super-sampling (and I’m not sure whether many of those are even available - even engines like Skia don’t do it) then it’s just not practical to render adjacent blocks without sub-pixel artefacts. Tom and I were mulling over how difficult it’d be to write a juce renderer that does tiling + supersampling rather than normal anti-aliasing, and may experiment with it if we have time next year, but no promises.
Interesting read. Just ran into the same problem.
About your workaround: Just be aware of this: if a component is setPaintingIsUnclipped(), it will always get repainted whenever its child is repainted!
So you might see worse UI performance.
See also this thread: