I’ll chime in on this to say that I believe it doesn’t make any difference, because once images are loaded from the original BMP or PNG file they come from, they have the same representation in memory which is file-format agnostic
That’s only half of the story: if your 100x100 component is scaled say 33% via a transform in JUCE, then getScreenBounds() will return the coordinates on screen which are 33x33, but those are logical points.
If your monitor is Retina, then every logical point is 2 physical pixels long, thus you will need an image that is 66x66 physical pixels to fill that same area without any rescaling.
You can get the physical scale factor within the paint call. I got good results checking whether I need to resample/prerender my own buffered background images there and doing it just in time.
Thanks @yfede Seems logical. How about Bmp vs png image loading is it comparable as well in juce?
IIRC both formats include potentially LZW compression (zip), so depending on settings when saving they might create overhead. But zip doesn’t make a processor sweat nowadays.
To minimise the load times make sure to use the juce::ImageCache. The images have shared pixel arrays, where the pixel data is uncompressed.
Thanks guys, your help is really valuable.
Putting this as a side talk since you have some good Lnf knowledge
Is it possible to change the Plugin host's window position with JUCE.? if let's say the plugin in cubase is in the middle of the screen, and a user clicks "advanced" that open a vertical extension, can we make the window go up and extend down to fit the screen? for now the window if the plugin is to big will go out of the screen
Thanks
If that is possible at all, it will be through the OS platform API. Usually a PluginEditor is wrapped into a native window handle, so the host can embed it without any knowledge if the plugin uses JUCE or not.
AFAIK, the host’s plugin window just observes the size of the editor so it can resize itself.
Grasping a straw would be going up the hierarchy to getTopLevelComponent(), grabbing the ComponentPeer and call setBounds there. But I wouldn’t be surprised, if you are just displaced and leave the host window behind.
Interesting, we’ll try and see. If anyone had a similar task with a vertical extension, feel free to manifest how you did this in combinaison with allowing resizability
@FasterMaster there is no difference in file formats once loaded into a juce::Image. Use whatever works the easiest for you.
We use .webp for compressed stuff (think background pictures where the quality doesn’t have to be 100%, but still better than .jpg) and .png if we want everything pixel-perfect. I would never even consider a format like .bmp as it’s platform-specific, and other devs in our team may have difficulty previewing it in their OS. We also use a lot of .svg for icons.
To get the scale we use:
void MipMap::draw ( juce::Graphics& g, juce::Rectangle<float> rc, juce::RectanglePlacement placement )
{
if ( images.size () == 0 )
return;
auto img = &images[ 0 ];
if ( img->isNull () )
return;
const auto scale = g.getInternalContext ().getPhysicalPixelScaleFactor ();
const auto scaledRect = ( rc * scale ).toNearestInt ();
const auto mipRect = ( rc * scale * 1.25f ).toNearestInt ();
for ( auto& i : images )
if ( i.getWidth () > mipRect.getWidth () && i.getHeight () > mipRect.getHeight () )
img = &i;
else
break;
auto quality = ( img->getWidth () == scaledRect.getWidth () && img->getHeight () == scaledRect.getHeight () ) ?
juce::Graphics::lowResamplingQuality
:
juce::Graphics::highResamplingQuality;
g.setImageResamplingQuality ( quality );
g.drawImage ( *img, rc, placement );
}
images is an std::vector of juce::Images with [0] being the original size, [1] being 50%, [2] being 25%, etc.
Should the scaled rect come out to exactly the chosen mipmap (happens rarely, but is not impossible) we reduce the sampling-quality to ‘low’, to speed up drawing.
Is there a reason you don’t just scale the image once to the final target, rather than to discrete increments with a secondary scale to finish?
There are multiple reasons:
- The window might be dragged to another display with a different scale factor
- The user might change his display scale factor while the DAW is still running
- The user might use the bottom-right corner dragger we offer to re-scale the plugin
- We might want to display the same bitmap at different sizes
- We might want to be able to zoom the image dynamically for certain events
This is simply the most flexible way to handle it without sacrificing quality and performance.
If you plan to only scale once for the target resolution, you need a better resizer than JUCE can provide. This also means worse performance if the resize is needed. And some resize events you can’t even detect, like when your plugin window is dragged to another display. You would then need to detect the different scale in the paint function, and then trigger a resize to the new final size. Either you do the resize directly and cause a momentary stutter, or you trigger another thread to create the new scaled version and then have to call repaint again to “fix” the bad version you caused by using too large or too small a bitmap in the paint function.
This is the most elegant and fastest way we could come up with. It’s used a lot in the gaming industry.
You can take our NEXUS or Vanguard plugin window and change the size in real time, and there is neither a stutter nor a noticeable image quality problem ever. It’s very smooth and always looks its best.
Thanks for all the info you’ve presented here.
Stellar response from @reFX really helpful! Thanks
Have you found a way to deal with things like DrawableButton
objects? These I’d traditionally set new images for in the resized()
method.
We don’t use them.