Browse Source

Added Rogan knobs to components.hpp, added shadow to SVGKnob, fixed bug/typo in SVG stroke fill color

tags/v0.3.0
Andrew Belt 7 years ago
parent
commit
de44d0c754
9 changed files with 386 additions and 54 deletions
  1. +19
    -2
      include/app.hpp
  2. +246
    -10
      include/components.hpp
  3. +47
    -27
      include/math.hpp
  4. +2
    -0
      src/app/ModuleWidget.cpp
  5. +0
    -1
      src/app/Port.cpp
  6. +20
    -0
      src/app/SVGKnob.cpp
  7. +23
    -0
      src/app/SVGPort.cpp
  8. +1
    -0
      src/dsp.cpp
  9. +28
    -14
      src/widgets/SVGWidget.cpp

+ 19
- 2
include/app.hpp View File

@@ -141,6 +141,7 @@ struct SVGKnob : Knob, FramebufferWidget {
SVGKnob();
void setSVG(std::shared_ptr<SVG> svg);
void step();
void draw(NVGcontext *vg);
void onChange();
};

@@ -180,15 +181,16 @@ struct MomentarySwitch : virtual Switch {
// ports
////////////////////

struct Port : OpaqueWidget, SpriteWidget {
struct Port : OpaqueWidget {
enum PortType {
DEFAULT,
INPUT,
OUTPUT
};

Module *module = NULL;
WireWidget *connectedWire = NULL;
PortType type;
PortType type = DEFAULT;
int portId;

Port();
@@ -204,6 +206,21 @@ struct Port : OpaqueWidget, SpriteWidget {
void onDragLeave(Widget *origin);
};

struct SpritePort : Port, SpriteWidget {
void draw(NVGcontext *vg) {
Port::draw(vg);
SpriteWidget::draw(vg);
}
};

struct SVGPort : Port, FramebufferWidget {
SVGWidget *sw;

SVGPort();
void setSVG(std::shared_ptr<SVG> svg);
void draw(NVGcontext *vg);
};

////////////////////
// scene
////////////////////


+ 246
- 10
include/components.hpp View File

@@ -24,15 +24,239 @@ extern const NVGcolor colors[NUM_COLORS];
// Knobs
////////////////////

struct SynthTechAlco : SpriteKnob {
struct Rogan : SVGKnob {
Rogan() {
minAngle = -0.75*M_PI;
maxAngle = 0.75*M_PI;
}
};

struct Rogan6PS : Rogan {
Rogan6PS() {
box.size = Vec(89, 89);
minAngle = -0.83*M_PI;
maxAngle = 0.83*M_PI;
}
};

struct Rogan5PS : Rogan {
Rogan5PS() {
box.size = Vec(60, 60);
}
};

struct Rogan3PS : Rogan {
Rogan3PS() {
box.size = Vec(52, 52);
}
};

struct Rogan3P : Rogan {
Rogan3P() {
box.size = Vec(42, 42);
}
};

struct Rogan2S : Rogan {
Rogan2S() {
box.size = Vec(43, 43);
}
};

struct Rogan2PS : Rogan {
Rogan2PS() {
box.size = Vec(43, 43);
}
};

struct Rogan2P : Rogan {
Rogan2P() {
box.size = Vec(34, 34);
}
};

struct Rogan1PS : Rogan {
Rogan1PS() {
box.size = Vec(40, 40);
}
};

struct Rogan1P : Rogan {
Rogan1P() {
box.size = Vec(31, 31);
}
};


struct Rogan6PSWhite : Rogan6PS {
Rogan6PSWhite() {
setSVG(SVG::load("res/ComponentLibrary/Rogan6PSWhite.svg"));
}
};

struct Rogan5PSGray : Rogan5PS {
Rogan5PSGray() {
setSVG(SVG::load("res/ComponentLibrary/Rogan5PSGray.svg"));
}
};

struct Rogan3PSBlue : Rogan3PS {
Rogan3PSBlue() {
setSVG(SVG::load("res/ComponentLibrary/Rogan3PSBlue.svg"));
}
};

struct Rogan3PSRed : Rogan3PS {
Rogan3PSRed() {
setSVG(SVG::load("res/ComponentLibrary/Rogan3PSRed.svg"));
}
};

struct Rogan3PSGreen : Rogan3PS {
Rogan3PSGreen() {
setSVG(SVG::load("res/ComponentLibrary/Rogan3PSGreen.svg"));
}
};

struct Rogan3PSWhite : Rogan3PS {
Rogan3PSWhite() {
setSVG(SVG::load("res/ComponentLibrary/Rogan3PSWhite.svg"));
}
};

struct Rogan3PBlue : Rogan3P {
Rogan3PBlue() {
setSVG(SVG::load("res/ComponentLibrary/Rogan3PBlue.svg"));
}
};

struct Rogan3PRed : Rogan3P {
Rogan3PRed() {
setSVG(SVG::load("res/ComponentLibrary/Rogan3PRed.svg"));
}
};

struct Rogan3PGreen : Rogan3P {
Rogan3PGreen() {
setSVG(SVG::load("res/ComponentLibrary/Rogan3PGreen.svg"));
}
};

struct Rogan3PWhite : Rogan3P {
Rogan3PWhite() {
setSVG(SVG::load("res/ComponentLibrary/Rogan3PWhite.svg"));
}
};

struct Rogan2SGray : Rogan2S {
Rogan2SGray() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2SGray.svg"));
}
};

struct Rogan2PSBlue : Rogan2PS {
Rogan2PSBlue() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2PSBlue.svg"));
}
};

struct Rogan2PSRed : Rogan2PS {
Rogan2PSRed() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2PSRed.svg"));
}
};

struct Rogan2PSGreen : Rogan2PS {
Rogan2PSGreen() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2PSGreen.svg"));
}
};

struct Rogan2PSWhite : Rogan2PS {
Rogan2PSWhite() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2PSWhite.svg"));
}
};

struct Rogan2PBlue : Rogan2P {
Rogan2PBlue() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2PBlue.svg"));
}
};

struct Rogan2PRed : Rogan2P {
Rogan2PRed() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2PRed.svg"));
}
};

struct Rogan2PGreen : Rogan2P {
Rogan2PGreen() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2PGreen.svg"));
}
};

struct Rogan2PWhite : Rogan2P {
Rogan2PWhite() {
setSVG(SVG::load("res/ComponentLibrary/Rogan2PWhite.svg"));
}
};

struct Rogan1PSBlue : Rogan1PS {
Rogan1PSBlue() {
setSVG(SVG::load("res/ComponentLibrary/Rogan1PSBlue.svg"));
}
};

struct Rogan1PSRed : Rogan1PS {
Rogan1PSRed() {
setSVG(SVG::load("res/ComponentLibrary/Rogan1PSRed.svg"));
}
};

struct Rogan1PSGreen : Rogan1PS {
Rogan1PSGreen() {
setSVG(SVG::load("res/ComponentLibrary/Rogan1PSGreen.svg"));
}
};

struct Rogan1PSWhite : Rogan1PS {
Rogan1PSWhite() {
setSVG(SVG::load("res/ComponentLibrary/Rogan1PSWhite.svg"));
}
};

struct Rogan1PBlue : Rogan1P {
Rogan1PBlue() {
setSVG(SVG::load("res/ComponentLibrary/Rogan1PBlue.svg"));
}
};

struct Rogan1PRed : Rogan1P {
Rogan1PRed() {
setSVG(SVG::load("res/ComponentLibrary/Rogan1PRed.svg"));
}
};

struct Rogan1PGreen : Rogan1P {
Rogan1PGreen() {
setSVG(SVG::load("res/ComponentLibrary/Rogan1PGreen.svg"));
}
};

struct Rogan1PWhite : Rogan1P {
Rogan1PWhite() {
setSVG(SVG::load("res/ComponentLibrary/Rogan1PWhite.svg"));
}
};


struct SynthTechAlco : SVGKnob {
SynthTechAlco() {
box.size = Vec(45, 45);
spriteOffset = Vec(-3, -2);
spriteSize = Vec(51, 51);
minIndex = 49;
maxIndex = -51;
spriteCount = 120;
spriteImage = Image::load("res/ComponentLibrary/SynthTechAlco.png");
minAngle = -0.82*M_PI;
maxAngle = 0.82*M_PI;
setSVG(SVG::load("res/ComponentLibrary/SynthTechAlco.svg"));
}
};

@@ -62,6 +286,15 @@ struct Davies1900hRedKnob : Davies1900hKnob {
}
};

struct Trimpot : SVGKnob {
Trimpot() {
box.size = Vec(17, 17);
minAngle = -0.75*M_PI;
maxAngle = 0.75*M_PI;
setSVG(SVG::load("res/ComponentLibrary/Trimpot.svg"));
}
};

struct BefacoBigKnob : SVGKnob {
BefacoBigKnob() {
box.size = Vec(75, 75);
@@ -96,30 +329,33 @@ struct BefacoSlidePot : SpriteKnob {
// Jacks
////////////////////

struct PJ301MPort : Port {
struct PJ301MPort : SpritePort {
PJ301MPort() {
box.size = Vec(24, 24);
spriteOffset = Vec(-2, -2);
spriteSize = Vec(30, 30);
spriteImage = Image::load("res/ComponentLibrary/PJ301M.png");
// setSVG(SVG::load("res/ComponentLibrary/PJ301M.svg"));
}
};

struct PJ3410Port : Port {
struct PJ3410Port : SpritePort {
PJ3410Port() {
box.size = Vec(32, 31);
spriteOffset = Vec(-1, -1);
spriteSize = Vec(36, 36);
spriteImage = Image::load("res/ComponentLibrary/PJ3410.png");
// setSVG(SVG::load("res/ComponentLibrary/PJ3410.svg"));
}
};

struct CL1362Port : Port {
struct CL1362Port : SpritePort {
CL1362Port() {
box.size = Vec(33, 29);
spriteOffset = Vec(-2, -2);
spriteSize = Vec(39, 36);
spriteImage = Image::load("res/ComponentLibrary/CL1362.png");
// setSVG(SVG::load("res/ComponentLibrary/CL1362.svg"));
}
};



+ 47
- 27
include/math.hpp View File

@@ -5,6 +5,53 @@

namespace rack {

////////////////////
// integer functions
////////////////////

inline int mini(int a, int b) {
return a < b ? a : b;
}

inline int maxi(int a, int b) {
return a > b ? a : b;
}

inline int absi(int a) {
return a >= 0 ? a : -a;
}

// Euclidean modulus, always returns 0 <= mod < base for positive base
// Assumes this architecture's division is non-Euclidean
inline int eucmod(int a, int base) {
int mod = a % base;
return mod < 0 ? mod + base : mod;
}

inline int log2i(int n) {
int i = 0;
while (n >>= 1) {
i++;
}
return i;
}

inline bool ispow2(int n) {
return n > 0 && (n & (n - 1)) == 0;
}

////////////////////
// float functions
////////////////////

inline float radtodeg(float x) {
return x * (180.0 / M_PI);
}

inline float degtorad(float x) {
return x * (M_PI / 180.0);
}

/** Limits a value between a minimum and maximum
If min > max for some reason, returns min
*/
@@ -31,14 +78,6 @@ inline float crossf(float a, float b, float frac) {
return (1.0 - frac) * a + frac * b;
}

inline int mini(int a, int b) {
return a < b ? a : b;
}

inline int maxi(int a, int b) {
return a > b ? a : b;
}

inline float quadraticBipolar(float x) {
float x2 = x*x;
return x >= 0.0 ? x2 : -x2;
@@ -92,25 +131,6 @@ inline float interpf(const float *p, float x) {
return crossf(p[xi], p[xi+1], xf);
}

// Euclidean modulus, always returns 0 <= mod < base for positive base
// Assumes this architecture's division is non-Euclidean
inline int eucmod(int a, int base) {
int mod = a % base;
return mod < 0 ? mod + base : mod;
}

inline int log2i(int n) {
int i = 0;
while (n >>= 1) {
i++;
}
return i;
}

inline bool ispow2(int n) {
return n > 0 && (n & (n - 1)) == 0;
}

////////////////////
// 2D float vector
////////////////////


+ 2
- 0
src/app/ModuleWidget.cpp View File

@@ -23,11 +23,13 @@ void ModuleWidget::setModule(Module *module) {
}

void ModuleWidget::addInput(Port *input) {
assert(input->type == Port::INPUT);
inputs.push_back(input);
addChild(input);
}

void ModuleWidget::addOutput(Port *output) {
assert(output->type == Port::OUTPUT);
outputs.push_back(output);
addChild(output);
}


+ 0
- 1
src/app/Port.cpp View File

@@ -24,7 +24,6 @@ void Port::draw(NVGcontext *vg) {
if (type == INPUT ? gRackWidget->activeWire->inputPort : gRackWidget->activeWire->outputPort)
nvgGlobalAlpha(vg, 0.5);
}
SpriteWidget::draw(vg);
}

void Port::onMouseDown(int button) {


+ 20
- 0
src/app/SVGKnob.cpp View File

@@ -35,6 +35,26 @@ void SVGKnob::step() {
FramebufferWidget::step();
}

void SVGKnob::draw(NVGcontext *vg) {
// Draw circular shadow below knob
// TODO This is a hack. Make a CircularShadow its own class
{
nvgBeginPath(vg);
float margin = 5.0;
nvgRect(vg, -margin, -margin, box.size.x + 2*margin, box.size.y + 2*margin);
nvgFillColor(vg, nvgRGBAf(0.0, 0.0, 0.0, 0.25));
Vec c = box.size.div(2.0);
float radius = c.x - 1;
NVGcolor icol = nvgRGBAf(0.0, 0.0, 0.0, 0.25);
NVGcolor ocol = nvgRGBAf(0.0, 0.0, 0.0, 0.0);
NVGpaint paint = nvgRadialGradient(vg, c.x, c.y + 1, radius, radius + 3, icol, ocol);
nvgFillPaint(vg, paint);
nvgFill(vg);
}

FramebufferWidget::draw(vg);
}

void SVGKnob::onChange() {
dirty = true;
ParamWidget::onChange();


+ 23
- 0
src/app/SVGPort.cpp View File

@@ -0,0 +1,23 @@
#include "app.hpp"


namespace rack {


SVGPort::SVGPort() {
sw = new SVGWidget();
setScene(sw);
}

void SVGPort::setSVG(std::shared_ptr<SVG> svg) {
sw->svg = svg;
sw->wrap();
}

void SVGPort::draw(NVGcontext *vg) {
Port::draw(vg);
FramebufferWidget::draw(vg);
}


} // namespace rack

src/dsp.cpp
File diff suppressed because it is too large
View File


+ 28
- 14
src/widgets/SVGWidget.cpp View File

@@ -1,31 +1,42 @@
#include "widgets.hpp"


// #define DEBUG_ONLY(x) x
#define DEBUG_ONLY(x)

namespace rack {


static NVGcolor getNVGColor(int color) {
return nvgRGBA((color >> 0) & 0xff, (color >> 8) & 0xff, (color >> 16) & 0xff, (color >> 24) & 0xff);
// return nvgRGBA((color >> 24) & 0xff, (color >> 16) & 0xff, (color >> 8) & 0xff, (color) & 0xff);
static NVGcolor getNVGColor(uint32_t color) {
return nvgRGBA(
(color >> 0) & 0xff,
(color >> 8) & 0xff,
(color >> 16) & 0xff,
(color >> 24) & 0xff);
}

static void drawSVG(NVGcontext *vg, NSVGimage *svg) {
for (NSVGshape *shape = svg->shapes; shape; shape = shape->next) {
// printf(" new shape: id \"%s\", fillrule %d\n", shape->id, shape->fillRule);
DEBUG_ONLY(printf("new image: %g x %g px\n", svg->width, svg->height);)
int shapeIndex = 0;
for (NSVGshape *shape = svg->shapes; shape; shape = shape->next, shapeIndex++) {
DEBUG_ONLY(printf(" new shape: %d id \"%s\", fillrule %d\n", shapeIndex, shape->id, shape->fillRule);)

if (!(shape->flags & NSVG_FLAGS_VISIBLE))
continue;

nvgSave(vg);
nvgGlobalAlpha(vg, shape->opacity);

if (shape->opacity < 1.0)
nvgGlobalAlpha(vg, shape->opacity);

nvgStrokeWidth(vg, shape->strokeWidth);
// strokeDashOffset, strokeDashArray, strokeDashCount not supported
// strokeLineJoin, strokeLineCap not supported
// strokeDashOffset, strokeDashArray, strokeDashCount not yet supported
// strokeLineJoin, strokeLineCap not yet supported

// Build path
nvgBeginPath(vg);
for (NSVGpath *path = shape->paths; path; path = path->next) {
// printf(" new path: %d points, %s\n", path->npts, path->closed ? "closed" : "notclosed");
DEBUG_ONLY(printf(" new path: %d points, %s\n", path->npts, path->closed ? "closed" : "open");)

nvgMoveTo(vg, path->pts[0], path->pts[1]);
for (int i = 1; i < path->npts; i += 3) {
@@ -37,7 +48,6 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) {
if (path->closed)
nvgClosePath(vg);


if (path->next)
nvgPathWinding(vg, NVG_HOLE);
}
@@ -48,7 +58,7 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) {
case NSVG_PAINT_COLOR: {
NVGcolor color = getNVGColor(shape->fill.color);
nvgFillColor(vg, color);
// printf(" fill color (%f %f %f %f)\n", color.r, color.g, color.b, color.a);
DEBUG_ONLY(printf(" fill color (%g, %g, %g, %g)\n", color.r, color.g, color.b, color.a);)
} break;
case NSVG_PAINT_LINEAR_GRADIENT: {
// NSVGgradient *g = shape->fill.gradient;
@@ -63,8 +73,8 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) {
switch (shape->stroke.type) {
case NSVG_PAINT_COLOR: {
NVGcolor color = getNVGColor(shape->stroke.color);
nvgFillColor(vg, color);
// printf(" stroke color (%f %f %f %f)\n", color.r, color.g, color.b, color.a);
nvgStrokeColor(vg, color);
DEBUG_ONLY(printf(" stroke color (%g, %g, %g, %g)\n", color.r, color.g, color.b, color.a);)
} break;
case NSVG_PAINT_LINEAR_GRADIENT: {
// NSVGgradient *g = shape->stroke.gradient;
@@ -76,6 +86,8 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) {

nvgRestore(vg);
}

DEBUG_ONLY(printf("\n");)
}


@@ -87,7 +99,9 @@ void SVGWidget::wrap() {
}

void SVGWidget::draw(NVGcontext *vg) {
drawSVG(vg, svg->handle);
if (svg && svg->handle) {
drawSVG(vg, svg->handle);
}
}




Loading…
Cancel
Save