Skip to content

Commit

Permalink
More tweaks to the graphics backend
Browse files Browse the repository at this point in the history
  • Loading branch information
kunitoki committed May 9, 2024
1 parent f2168dc commit 9046826
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 97 deletions.
191 changes: 114 additions & 77 deletions examples/graphics/source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,94 +30,137 @@

//==============================================================================

class CustomComponent : public juce::Component
class CustomSlider : public juce::Component
{
int index = 0;

public:
CustomComponent()
CustomSlider (int index)
: index (index)
{
random.setSeedRandomly();
}

void mouseDown (const juce::MouseEvent& event) override
{
origin = event.getPosition();

DBG ("Hit: " << index);
}

void mouseUp (const juce::MouseEvent& event) override
{
}

void mouseDrag (const juce::MouseEvent& event) override
{
//auto [x, y] = event.getPosition();

const float distance = origin.distanceX (event.getPosition()) * 0.005f;
origin = event.getPosition();

value = juce::jlimit (0.0f, 1.0f, value + distance);
}

void paint (juce::Graphics& g, float frameRate) override
{
auto bounds = getLocalBounds().reduced (proportionOfWidth (0.1f));

juce::Path path;
path.addEllipse (bounds.reduced (proportionOfWidth (0.1f)));

g.setColor (0xff3d3d3d);
g.fillPath (path);

g.setColor (0xff2b2b2b);
g.drawPath (path, proportionOfWidth (0.01f));

const auto fromRadians = juce::degreesToRadians(135.0f);
const auto toRadians = fromRadians + juce::degreesToRadians(270.0f);
const auto toCurrentRadians = fromRadians + juce::degreesToRadians(270.0f) * value;

const auto center = bounds.to<float>().getCenter();

juce::Path arc;

{
arc.addCenteredArc (center,
bounds.getWidth() / 2.0f, bounds.getHeight() / 2.0f, 0.0f,
fromRadians, toRadians, true);

g.setStrokeCap (juce::StrokeCap::Butt);
g.setColor (0xff636363);
g.drawPath (arc, proportionOfWidth (0.1f));
}

{
arc.clear();
arc.addCenteredArc (center,
bounds.getWidth() / 2.0f, bounds.getHeight() / 2.0f, 0.0f,
fromRadians, toCurrentRadians, true);

g.setStrokeCap (juce::StrokeCap::Round);
g.setColor (0xff4ebfff);
g.drawPath (arc, proportionOfWidth (0.1f));
}

{
const auto reducedBounds = bounds.reduced (proportionOfWidth (0.175f));

auto pos = center.getPointOnCircumference (
reducedBounds.getWidth() / 2.0f,
reducedBounds.getHeight() / 2.0f,
toCurrentRadians);

arc.clear();
arc.addLine (juce::Line<float> (pos, center).keepOnlyStart (0.2f));

g.setStrokeCap (juce::StrokeCap::Round);
g.setColor (0xffffffff);
g.drawPath (arc, proportionOfWidth (0.04f));
}
}

private:
juce::Random& random = juce::Random::getSystemRandom();
juce::Point<float> origin;
float value = 0.0f;
};

//==============================================================================

class CustomWindow : public juce::DocumentWindow
{
CustomComponent c;
juce::OwnedArray<CustomSlider> sliders;
int totalRows = 4;
int totalColumns = 4;

public:
CustomWindow()
{
addAndMakeVisible (c);
for (int i = 0; i < totalRows * totalColumns; ++i)
addAndMakeVisible (sliders.add (std::make_unique<CustomSlider> (i)));
}

void resized() override
{
c.setBounds (getLocalBounds().reduced (100));
}
auto bounds = getLocalBounds().reduced (200);
auto width = bounds.getWidth() / totalColumns;
auto height = bounds.getHeight() / totalRows;

void paint (juce::Graphics& g, float frameRate) override
{
double time = juce::Time::getMillisecondCounterHiRes() / 1000.0;

auto renderer = g.getRenderer();
auto factory = g.getFactory();

rive::float2 p[9];
for (int i = 0; i < 9; ++i)
p[i] = pts[i] + translate;

rive::RawPath rawPath;
rawPath.moveTo (p[0].x, p[0].y);
rawPath.cubicTo (p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y);
rive::float2 c0 = rive::simd::mix (p[3], p[4], rive::float2 (2 / 3.f));
rive::float2 c1 = rive::simd::mix (p[5], p[4], rive::float2 (2 / 3.f));
rawPath.cubicTo (c0.x, c0.y, c1.x, c1.y, p[5].x, p[5].y);
rawPath.cubicTo (p[6].x, p[6].y, p[7].x, p[7].y, p[8].x, p[8].y);
if (doClose)
rawPath.close();

auto path = factory->makeRenderPath (rawPath, rive::FillRule::nonZero);

auto fillPaint = factory->makeRenderPaint();
fillPaint->style (rive::RenderPaintStyle::fill);
fillPaint->color (-1);

auto strokePaint = factory->makeRenderPaint();
strokePaint->style (rive::RenderPaintStyle::stroke);
strokePaint->color (0x8000ffff);
strokePaint->thickness (strokeWidth);
strokePaint->join (join);
strokePaint->cap (cap);

renderer->drawPath (path.get(), fillPaint.get());
renderer->drawPath (path.get(), strokePaint.get());

// Draw the interactive points.
auto pointPaint = factory->makeRenderPaint();
pointPaint->style (rive::RenderPaintStyle::stroke);
pointPaint->color (0xff0000ff);
pointPaint->thickness (14);
pointPaint->cap (rive::StrokeCap::round);

auto pointPath = factory->makeEmptyRenderPath();
for (int i : { 1, 2, 4, 6, 7 })
for (int i = 0; i < totalRows; ++i)
{
rive::float2 pt = pts[i] + translate;
pointPath->moveTo (pt.x, pt.y);
auto row = bounds.removeFromTop (height);
for (int j = 0; j < totalColumns; ++j)
{
auto col = row.removeFromLeft (width);
sliders.getUnchecked (i * totalRows + j)->setBounds (col.largerSquareFitting());
}
}
}

renderer->drawPath (pointPath.get(), pointPaint.get());

void paint (juce::Graphics& g, float frameRate) override
{
const double time = juce::Time::getMillisecondCounterHiRes() / 1000.0;
updateFrameTime (time);
updateWindowTitle();
}

void mouseDown (const juce::MouseEvent& event) override
Expand Down Expand Up @@ -174,7 +217,6 @@ class CustomWindow : public juce::DocumentWindow
case juce::KeyPress::textAKey:
forceAtomicMode = !forceAtomicMode;
fpsLastTime = 0;
fpsFrames = 0;
break;

case juce::KeyPress::textDKey:
Expand Down Expand Up @@ -232,6 +274,18 @@ class CustomWindow : public juce::DocumentWindow
}

private:
void updateFrameTime (double time)
{
double fpsElapsed = time - fpsLastTime;
if (fpsElapsed > 1)
{
currentFps = getNativeComponent()->getCurrentFrameRate();
updateWindowTitle();

fpsLastTime = time;
}
}

void updateWindowTitle()
{
juce::String title;
Expand All @@ -247,22 +301,6 @@ class CustomWindow : public juce::DocumentWindow
setTitle (title);
}

void updateFrameTime (double time)
{
++fpsFrames;

double fpsElapsed = time - fpsLastTime;
if (fpsElapsed > 1)
{
currentFps = fpsLastTime == 0 ? 0 : fpsFrames / fpsElapsed;

updateWindowTitle ();

fpsFrames = 0;
fpsLastTime = time;
}
}

bool forceAtomicMode = false;
bool wireframe = false;
bool disableFill = false;
Expand Down Expand Up @@ -294,7 +332,6 @@ class CustomWindow : public juce::DocumentWindow
int lastWidth = 0, lastHeight = 0;
double fpsLastTime = 0;
double currentFps = 0;
int fpsFrames = 0;
};

//==============================================================================
Expand Down
33 changes: 33 additions & 0 deletions modules/yup_graphics/primitives/yup_Rectangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,28 @@ class JUCE_API Rectangle
return *this;
}

constexpr Rectangle& reduce (ValueType deltaX, ValueType deltaY) noexcept
{
xy = { xy.getX() + deltaX, xy.getY() + deltaY };
size = { jmax (0, size.getWidth () - 2 * deltaX), jmax (0, size.getHeight () - 2 * deltaY) };

return *this;
}

constexpr Rectangle reduced (ValueType delta) noexcept
{
Rectangle result = *this;
result.reduce (delta);
return result;
}

constexpr Rectangle reduced (ValueType deltaX, ValueType deltaY) noexcept
{
Rectangle result = *this;
result.reduce (deltaX, deltaY);
return result;
}

//==============================================================================
constexpr bool contains (ValueType x, ValueType y) const noexcept
{
Expand All @@ -295,6 +310,24 @@ class JUCE_API Rectangle
return contains (p.getX(), p.getY());
}

//==============================================================================
constexpr Rectangle largerSquareFitting() const noexcept
{
if (getWidth() == getHeight())
return *this;

if (getWidth() > getHeight())
{
const auto newPosX = static_cast<ValueType> ((getWidth() - getHeight()) / 2.0f);
return { xy.getX() + newPosX, xy.getY(), getHeight(), getHeight() };
}
else
{
const auto newPosY = static_cast<ValueType> ((getHeight() - getWidth()) / 2.0f);
return { xy.getX(), xy.getY() + newPosY, getWidth(), getWidth() };
}
}

//==============================================================================
template <class T>
constexpr Rectangle<T> to() const noexcept
Expand Down
12 changes: 8 additions & 4 deletions modules/yup_graphics/primitives/yup_Size.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,31 +72,35 @@ class JUCE_API Size

//==============================================================================
template <class T>
constexpr auto operator* (T scaleFactor) const noexcept -> std::enable_if_t<std::is_floating_point_v<T>, Size>
constexpr auto operator* (T scaleFactor) const noexcept
-> std::enable_if_t<std::is_floating_point_v<T>, Size>
{
Size r (*this);
r *= scaleFactor;
return r;
}

template <class T>
constexpr auto operator*= (T scaleFactor) noexcept -> std::enable_if_t<std::is_floating_point_v<T>, Size&>
constexpr auto operator*= (T scaleFactor) noexcept
-> std::enable_if_t<std::is_floating_point_v<T>, Size&>
{
width = static_cast<ValueType> (width * scaleFactor);
height = static_cast<ValueType> (height * scaleFactor);
return *this;
}

template <class T>
constexpr auto operator/ (T scaleFactor) const noexcept -> std::enable_if_t<std::is_floating_point_v<T>, Size>
constexpr auto operator/ (T scaleFactor) const noexcept
-> std::enable_if_t<std::is_floating_point_v<T>, Size>
{
Size r (*this);
r /= scaleFactor;
return r;
}

template <class T>
constexpr auto operator/= (T scaleFactor) noexcept -> std::enable_if_t<std::is_floating_point_v<T>, Size&>
constexpr auto operator/= (T scaleFactor) noexcept
-> std::enable_if_t<std::is_floating_point_v<T>, Size&>
{
width = static_cast<ValueType> (width / scaleFactor);
height = static_cast<ValueType> (height / scaleFactor);
Expand Down
Loading

0 comments on commit 9046826

Please sign in to comment.