Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI update #23

Merged
merged 3 commits into from
Nov 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
319 changes: 163 additions & 156 deletions src/LatticeComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@

#include "JIMath.h"
#include "LatticesBinary.h"
// #include "LatticesAssets.h"

#include <algorithm>
#include <array>
#include <cmath>

#include <melatonin_blur/melatonin_blur.h>

Expand Down Expand Up @@ -49,17 +52,11 @@ struct LatticeComponent : juce::Component
auto nV = std::ceil(getHeight() / vDistance);
auto nW = std::ceil(getWidth() / hDistance);

juce::Image litSpheres{juce::Image::ARGB, getWidth(), getHeight(), true};
juce::Image unlitSpheres{juce::Image::ARGB, getWidth(), getHeight(), true};
juce::Image sphereBackgrounds{juce::Image::ARGB, getWidth(), getHeight(), true};
juce::Image litLines{juce::Image::ARGB, getWidth(), getHeight(), true};
juce::Image unlitLines{juce::Image::ARGB, getWidth(), getHeight(), true};
juce::Image Lines{juce::Image::ARGB, getWidth(), getHeight(), true};
juce::Image Spheres{juce::Image::ARGB, getWidth(), getHeight(), true};
{
juce::Graphics lS(litSpheres);
juce::Graphics uS(unlitSpheres);
juce::Graphics sB(sphereBackgrounds);
juce::Graphics lL(litLines);
juce::Graphics uL(unlitLines);
juce::Graphics lG(Lines);
juce::Graphics sG(Spheres);
for (int v = -nV - 1; v < nV + 1; ++v)
{
float off = v * hDistance * 0.5f;
Expand All @@ -74,81 +71,41 @@ struct LatticeComponent : juce::Component
if (x < 0 || x > getWidth())
continue;

bool sphereLit{false}, horizLit{false}, upLit{false}, downLit{false};
std::pair<int, int> C = {w, v}; // current sphere
for (int i = 0; i < 12; ++i)
{
if (C == CoO[i])
{
sphereLit = true;
break;
}
}
if (sphereLit)
{
std::pair<int, int> H = {w + 1, v}; // next one over
std::pair<int, int> U = {w, v + 1}; // next one up
std::pair<int, int> D = {w + 1, v - 1}; // next one down
for (int i = 0; i < 12; ++i)
{
if (H == CoO[i])
horizLit = true;
if (U == CoO[i])
upLit = true;
if (D == CoO[i])
downLit = true;
}
}
std::pair<int, int> C = {w, v}; // current sphere
std::pair<int, int> H = {w + 1, v}; // next one over
std::pair<int, int> U = {w, v + 1}; // next one up
std::pair<int, int> D = {w + 1, v - 1}; // next one down

// ok, so how far is this sphere from a lit up one?
auto dist = calcDist(C);
// and what about its lines?
auto hDist = std::max(dist, calcDist(H));
auto uDist = std::max(dist, calcDist(U));
auto dDist = std::max(dist, calcDist(D));
// those numbers will set this
float alpha{};

// Horizontal Line
if (horizLit)
{
lL.setColour(juce::Colours::white.withAlpha(1.f));
juce::Line<float> horiz(x, y, x + hDistance, y);
lL.drawLine(horiz, 3.f);
}
else
{
uL.setColour(juce::Colours::white.withAlpha(.75f));
juce::Line<float> horiz(x, y, x + hDistance, y);
uL.drawLine(horiz, 3.f);
}
alpha = 1.f / (std::sqrt(hDist) + 1);
lG.setColour(juce::Colours::white.withAlpha(alpha));
juce::Line<float> horiz(x, y, x + hDistance, y);
lG.drawLine(horiz, 3.f);

// Upward Line
if (upLit)
{
lL.setColour(juce::Colours::white.withAlpha(1.f));
juce::Line<float> up(x, y, x + (hDistance * .5f), y - vDistance);
float l[2] = {7.f, 3.f};
lL.drawDashedLine(up, l, 2, 3.f, 1);
}
else
{
uL.setColour(juce::Colours::white.withAlpha(.75f));
juce::Line<float> up(x, y, x + (hDistance * .5f), y - vDistance);
float l[2] = {7.f, 3.f};
uL.drawDashedLine(up, l, 2, 3.f, 1);
}
alpha = 1.f / (std::sqrt(uDist) + 1);
lG.setColour(juce::Colours::white.withAlpha(alpha));
juce::Line<float> up(x, y, x + (hDistance * .5f), y - vDistance);
float ul[2] = {7.f, 3.f};
lG.drawDashedLine(up, ul, 2, 3.f, 1);

// Downward Line
if (downLit)
{
lL.setColour(juce::Colours::white.withAlpha(1.f));
juce::Line<float> down(x, y, x + (hDistance * .5f), y + vDistance);
float l[2] = {2.f, 3.f};
lL.drawDashedLine(down, l, 2, 3.f, 1);
}
else
{
uL.setColour(juce::Colours::white.withAlpha(.75f));
juce::Line<float> down(x, y, x + (hDistance * .5f), y + vDistance);
float l[2] = {2.f, 3.f};
uL.drawDashedLine(down, l, 2, 3.f, 1);
}
alpha = 1.f / (std::sqrt(dDist) + 1);
lG.setColour(juce::Colours::white.withAlpha(alpha));
juce::Line<float> down(x, y, x + (hDistance * .5f), y + vDistance);
float dl[2] = {2.f, 3.f};
lG.drawDashedLine(down, dl, 2, 3.f, 1);

// Sphere Backgrounds
auto ellipseRadius = JIRadius * 1.15;

auto gradient = juce::ColourGradient{};
// Select gradient colour
if ((w + (v * 4)) % 12 == 0)
Expand Down Expand Up @@ -190,57 +147,143 @@ struct LatticeComponent : juce::Component
b.addEllipse(x - ellipseRadius - 1.5, y - JIRadius - 1.5, 2 * ellipseRadius + 3,
2 * JIRadius + 3);

alpha = 1.f / (std::sqrt(dist) + 1);
// draw those
whiteShadow.setOpacity(alpha);
whiteShadow.render(sG, e);
blackShadow.setOpacity(alpha);
blackShadow.render(sG, b);
sG.setColour(juce::Colours::black);
sG.fillPath(b);
gradient.multiplyOpacity(alpha);
sG.setGradientFill(gradient);
sG.fillPath(e);
sG.setColour(juce::Colours::white.withAlpha(alpha));
sG.drawEllipse(x - ellipseRadius, y - JIRadius, 2 * ellipseRadius, 2 * JIRadius,
3);

// Names or Ratios?
auto [n, d] = calculateCell(w, v);
auto s = std::to_string(n) + "/" + std::to_string(d);
// std::string s = jim.nameNoteOnLattice(w, v);
// auto [n,d] = calculateCell(w, v);
// auto s = std::to_string(n) + "/" + std::to_string(d);
std::string s = jim.nameNoteOnLattice(w, v);
sG.setFont(stoke);
sG.drawFittedText(s, x - ellipseRadius + 3, y - (JIRadius / 3.f),
2.f * (ellipseRadius - 3), .66667f * JIRadius,
juce::Justification::horizontallyCentred, 1, 0.05f);
}
}
}
g.drawImageAt(Lines, 0, 0, false);
g.drawImageAt(Spheres, 0, 0, false);
}

if (sphereLit)
{
whiteShadow.render(lS, e);
blackShadow.render(lS, b);
lS.setColour(juce::Colours::black);
lS.fillPath(b);
gradient.multiplyOpacity(1.f);
lS.setGradientFill(gradient);
lS.fillPath(e);
lS.setColour(juce::Colours::white);
lS.drawEllipse(x - ellipseRadius, y - JIRadius, 2 * ellipseRadius,
2 * JIRadius, 3);
lS.setFont(stoke);
lS.drawFittedText(s, x - ellipseRadius + 3, y - (JIRadius / 3.f),
2.f * (ellipseRadius - 3), .66667f * JIRadius,
juce::Justification::horizontallyCentred, 1, 0.05f);
}
else
protected:
static constexpr int JIRadius{26};
JIMath jim;

juce::ReferenceCountedObjectPtr<juce::Typeface> Stoke{juce::Typeface::createSystemTypefaceFor(
LatticesBinary::Stoke_otf, LatticesBinary::Stoke_otfSize)};

juce::Font stoke{juce::FontOptions(Stoke).withPointHeight(JIRadius)};

juce::Colour com1{0.f, .84f, 1.f, 1.f};
juce::Colour com2{.961111f, .79f, .41f, .25f};

juce::Colour p1{.5f, .51f, .3f, 1.f};
juce::Colour p2{.5277778f, .79f, .41f, .25f};

juce::Colour l1c1{.35f, .75f, .98f, 1.f};
juce::Colour l1c2{.5277778f, .79f, .41f, .25f};

juce::Colour l2c1{.2888889f, .97f, .67f, 1.f};
juce::Colour l2c2{.6194444f, .71f, 1.f, .25f};

juce::Colour l3c1{.6916667f, .97f, .76f, 1.f};
juce::Colour l3c2{.4361111f, 1.f, .59f, .61f};

juce::Colour l4c1{.5777778f, .97f, .94f, 58.f};
juce::Colour l4c2{.8666667f, 1.f, .36f, 1.f};

melatonin::DropShadow blackShadow = {juce::Colours::black, 8};
melatonin::DropShadow whiteShadow = {juce::Colours::antiquewhite, 12};

std::array<std::pair<int, int>, 12> CoO{}; // currently lit co-ordinates

inline int calcDist(std::pair<int, int> xy) // how far is a given coordinate from those?
{
auto inside = std::find(CoO.begin(), CoO.end(), xy);
int xDist{CoO[0].first};
int yDist{CoO[0].second};

if (inside != CoO.end()) // we're on a lit note
{
return 0;
}
else // if we aren't, find out how far
{
// find X distance first
if (xy.first < CoO[5].first)
{
xDist = CoO[5].first - xy.first;
}
else if (xy.first > CoO[2].first)
{
xDist = xy.first - CoO[2].first;
}
else
{
xDist = 0; // We're over or under a lit note
// we need to know which column we're in for Syntonic mode.
auto x = xy.first;

std::array<int, 3> ys;
int it{0};

for (int i = 0; i < 12; ++i)
{
if (CoO[i].first == x)
{
whiteShadow.render(uS, e);
blackShadow.render(uS, b);
uS.setColour(juce::Colours::black);
uS.fillPath(b);
gradient.multiplyOpacity(.75f);
uS.setGradientFill(gradient);
uS.fillPath(e);
uS.setColour(juce::Colours::white.withAlpha(.75f));
uS.drawEllipse(x - ellipseRadius, y - JIRadius, 2 * ellipseRadius,
2 * JIRadius, 3);
// auto pst = juce::PathStrokeType(3.f);
// uS.strokePath(e, pst);
uS.setFont(stoke);
uS.drawFittedText(s, x - ellipseRadius + 3, y - (JIRadius / 3.f),
2.f * (ellipseRadius - 3), .66667f * JIRadius,
juce::Justification::horizontallyCentred, 1, 0.05f);
ys[it] = CoO[i].second;
++it;
}
}
// highest and lowest Y of this column
int top = *std::max_element(ys.begin(), ys.end());
int bottom = *std::min_element(ys.begin(), ys.end());

// so now find y dist
if (xy.second < bottom)
{
yDist = bottom - xy.second;
}
else if (xy.second > top)
{
yDist = xy.second - top;
}

auto res = std::max(xDist, yDist);
return res;
}

// ok if we made it here we're off to the sides somewhere
int top = CoO[4].second;
int bottom = CoO[8].second;

if (xy.second < bottom)
{
yDist = bottom - xy.second;
}
else if (xy.second > top)
{
yDist = xy.second - top;
}
}
g.drawImageAt(blur.render(unlitLines), 0, 0, false);
g.drawImageAt(litLines, 0, 0, false);
g.drawImageAt(blur.render(unlitSpheres), 0, 0, false);
g.drawImageAt(litSpheres, 0, 0, false);

auto res = std::max(xDist, yDist);
return res;
}

std::pair<uint64_t, uint64_t> calculateCell(int fifths, int thirds)
inline std::pair<uint64_t, uint64_t> calculateCell(int fifths, int thirds)
{
uint64_t n{1}, d{1};

Expand Down Expand Up @@ -282,40 +325,4 @@ struct LatticeComponent : juce::Component

return {n, d};
}

protected:
static constexpr int JIRadius{26};
JIMath jim;

juce::ReferenceCountedObjectPtr<juce::Typeface> Stoke{juce::Typeface::createSystemTypefaceFor(
LatticesBinary::Stoke_otf, LatticesBinary::Stoke_otfSize)};

juce::Font stoke{juce::FontOptions(Stoke).withPointHeight(JIRadius - 3)};

juce::Colour com1{0.f, .84f, 1.f, 1.f};
juce::Colour com2{.961111f, .79f, .41f, .25f};

juce::Colour p1{.5f, .51f, .3f, 1.f};
juce::Colour p2{.5277778f, .79f, .41f, .25f};

juce::Colour l1c1{.35f, .75f, .98f, 1.f};
juce::Colour l1c2{.5277778f, .79f, .41f, .25f};

juce::Colour l2c1{.2888889f, .97f, .67f, 1.f};
juce::Colour l2c2{.6194444f, .71f, 1.f, .25f};

juce::Colour l3c1{.6916667f, .97f, .76f, 1.f};
juce::Colour l3c2{.4361111f, 1.f, .59f, .61f};

juce::Colour l4c1{.5777778f, .97f, .94f, 58.f};
juce::Colour l4c2{.8666667f, 1.f, .36f, 1.f};

melatonin::CachedBlur blur{3};
melatonin::DropShadow blackShadow = {juce::Colours::black, 8};
melatonin::DropShadow whiteShadow = {juce::Colours::antiquewhite, 12};

std::pair<int, int> CoO[12]{
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
}; // current co-ordinates
};
Loading