I’ve been messing around with motion blur on a meter all afternoon after being annoyed with one that looked a bit jittery. Thought it was interesting to see what looked best …
Any other suggestions on how to make the motion look better greatly appreciated
class BlurBar
:
public Component
{
public:
Colour bgColour { 0xff202020 };
Colour fgColour { 0xffd0d0d0 };
void setBlurEnable(bool shouldEnable)
{
blur = shouldEnable;
}
void setValue(float newValue)
{
value = newValue;
repaint();
}
void setBlurAlpha(double newAlpha)
{
alpha = float(newAlpha);
}
void paint (Graphics& g)
{
g.fillAll(bgColour);
auto rect = getLocalBounds().toFloat();
rect.setWidth(rect.getWidth() * value); // scale our meter
g.setColour(fgColour);
g.fillRect(rect); // paint it
if (blur && lastRect.getWidth() != rect.getWidth())
{
bool increasing = lastRect.getWidth() < rect.getWidth();
float x1, x2;
if (increasing)
{
x1 = lastRect.getRight();
x2 = rect.getRight();
}
else
{
x1 = rect.getRight();
x2 = lastRect.getRight();
}
g.setGradientFill({
fgColour.withAlpha(alpha), x1, 0.0f,
bgColour.withAlpha(alpha), x2, 0.0f,
false
});
g.fillRect(x1, rect.getY(), x2 - x1, rect.getHeight());
}
lastRect = rect;
}
private:
Rectangle<float> lastRect;
bool blur{false};
float value{0.0f};
float alpha{0.0f};
};
class MainContentComponent : public Component, Timer, Slider::Listener, Button::Listener
{
public:
LookAndFeel_V3 lookAndFeel;
MainContentComponent()
{
getLookAndFeel().setDefaultLookAndFeel(&lookAndFeel);
blurEnableButton.addListener(this);
blurEnableButton.setClickingTogglesState(true);
blurEnableButton.setColour(TextButton::buttonColourId, Colour{0xff15BB58}.withMultipliedBrightness(0.2f));
blurEnableButton.setColour(TextButton::buttonOnColourId, Colour{0xff15BB58});
framerateSlider.setRange(5.0, 200.0, 1.0);
framerateSlider.setSkewFactor(0.5);
framerateSlider.setColour(Slider::thumbColourId, Colour{0xffFFA71D});
configSlider(framerateSlider);
incrementSlider.setRange(0.0, 0.1, 0.001);
incrementSlider.setColour(Slider::thumbColourId, Colour{0xff205FAB});
configSlider(incrementSlider);
blurAlphaSlider.setRange(0.0, 1.0, 0.001);
blurAlphaSlider.setColour(Slider::thumbColourId, Colour{0xffFF481D});
configSlider(blurAlphaSlider);
setDefaults();
startTimer(framerateSlider.getValue());
controls.push_back(&framerateSlider);
labels.push_back("Frame Rate");
controls.push_back(&incrementSlider);
labels.push_back("Speed");
controls.push_back(&blurEnableButton);
labels.push_back("Blur");
controls.push_back(&blurAlphaSlider);
labels.push_back("Blur Alpha");
for (auto c: controls)
addAndMakeVisible(c);
addAndMakeVisible(blurBar);
setSize (600, 400);
}
void configSlider(Slider & slider)
{
slider.addListener(this);
slider.setSliderStyle(Slider::LinearBarVertical);
slider.setColour(Slider::textBoxOutlineColourId, Colours::transparentBlack);
slider.setColour(Slider::textBoxTextColourId, Colours::lightgrey);
}
void buttonClicked(Button *)
{
bool buttonDown = blurEnableButton.getToggleState();
if (buttonDown)
blurEnableButton.setButtonText("ON");
else
blurEnableButton.setButtonText("OFF");
blurBar.setBlurEnable(buttonDown);
}
void setDefaults()
{
framerateSlider.setValue(1.0f);
incrementSlider.setValue(0.05f);
blurEnableButton.setToggleState(true, sendNotification);
blurAlphaSlider.setValue(0.5f);
}
void paint (Graphics& g)
{
g.fillAll(blurBar.bgColour);
g.setColour(blurBar.fgColour);
{
g.setFont(Font("Century Gothic", 20.0, 0));
auto r = getLocalBounds().withY(100).withHeight(30);
auto w = getWidth() / labels.size();
for (auto l: labels)
g.drawText(l, r.removeFromLeft(w), Justification::centred, false);
}
g.setColour(blurBar.fgColour.withAlpha(0.5f));
g.drawText("Shows the effect of motion blur at various speeds and framerates",
0, getHeight() - 40, getWidth(), 20, Justification::centred, false);
}
private:
void timerCallback()
{
auto inc = incrementSlider.getValue();
value += direction * inc * (framerateSlider.getValue() / 30.0);
if (value < 0.0f)
{
direction = 1.0f;
value = -value;
}
if (value > 1.0f)
{
direction = -1.0f;
value -= (value - 1.0f);
}
blurBar.setValue(value);
}
void resized()
{
auto area = getLocalBounds().withHeight(100);
auto w = area.getWidth() / controls.size();
for (auto c: controls)
c->setBounds(area.removeFromLeft(w));
blurBar.setBounds(getLocalBounds().withY(200).withHeight(20));
}
void sliderValueChanged(Slider * slider)
{
if (slider == &framerateSlider)
startTimer(std::round(framerateSlider.getValue()));
if (slider == &blurAlphaSlider)
blurBar.setBlurAlpha(blurAlphaSlider.getValue());
}
Slider framerateSlider;
Slider incrementSlider;
Slider blurAlphaSlider;
BlurBar blurBar;
std::vector<Component *> controls;
std::vector<String> labels;
float value {0.0f};
float direction {1.0f};
TextButton blurEnableButton{"Enable blur"};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};