Browse Source

Added TransformWidget, SVGWidget, FramebufferWidget

tags/v0.3.0
Andrew Belt 7 years ago
parent
commit
0e0f9c38f2
14 changed files with 375 additions and 133 deletions
  1. +1
    -1
      README.md
  2. +1
    -1
      ext/nanovg
  3. +43
    -17
      include/components.hpp
  4. +1
    -2
      include/gui.hpp
  5. +12
    -0
      include/math.hpp
  6. +45
    -2
      include/widgets.hpp
  7. +19
    -0
      src/components.cpp
  8. +16
    -96
      src/gui.cpp
  9. +88
    -0
      src/widgets/FramebufferWidget.cpp
  10. +12
    -12
      src/widgets/Light.cpp
  11. +1
    -1
      src/widgets/ModuleWidget.cpp
  12. +95
    -0
      src/widgets/SVGWidget.cpp
  13. +40
    -0
      src/widgets/TransformWidget.cpp
  14. +1
    -1
      src/widgets/WireWidget.cpp

+ 1
- 1
README.md View File

@@ -18,6 +18,6 @@ Install dependencies
- [libsamplerate](http://www.mega-nerd.com/SRC/)
- GTK+-2.0 if Linux (for file open/save dialog)

Run `make ARCH=linux` or `make ARCH=windows` or `make ARCH=apple`
Run `make ARCH=lin` or `make ARCH=win` or `make ARCH=mac`

If the build breaks because you think I've missed a step, feel free to post an issue.

+ 1
- 1
ext/nanovg

@@ -1 +1 @@
Subproject commit 8feae63a46fdf8ed83613b6a46da25d44adde07f
Subproject commit c629efbfa6ca90035d6625dfa3586048a9c3201f

+ 43
- 17
include/components.hpp View File

@@ -4,20 +4,38 @@

namespace rack {

#define SCHEME_BLACK nvgRGB(0x00, 0x00, 0x00)
#define SCHEME_WHITE nvgRGB(0xff, 0xff, 0xff)
#define SCHEME_RED nvgRGB(0xed, 0x2c, 0x24)
#define SCHEME_ORANGE nvgRGB(0xf2, 0xb1, 0x20)
#define SCHEME_YELLOW nvgRGB(0xf9, 0xdf, 0x1c)
#define SCHEME_GREEN nvgRGB(0x90, 0xc7, 0x3e)
#define SCHEME_CYAN nvgRGB(0x22, 0xe6, 0xef)
#define SCHEME_BLUE nvgRGB(0x29, 0xb2, 0xef)
#define SCHEME_PURPLE nvgRGB(0xd5, 0x2b, 0xed)

enum ColorNames {
COLOR_BLACK,
COLOR_WHITE,
COLOR_RED,
COLOR_ORANGE,
COLOR_YELLOW,
COLOR_GREEN,
COLOR_CYAN,
COLOR_BLUE,
COLOR_PURPLE,
NUM_COLORS
};

extern const NVGcolor colors[NUM_COLORS];

////////////////////
// Knobs
////////////////////

struct SynthTechAlco : SpriteKnob {
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");
}
};

struct KnobDavies1900h : SpriteKnob {
KnobDavies1900h() {
box.size = Vec(36, 36);
@@ -102,7 +120,7 @@ typedef PJ301M<OutputPort> OutputPortPJ301M;
template <typename BASE>
struct PJ3410 : BASE {
PJ3410() {
this->box.size = Vec(32, 32);
this->box.size = Vec(32, 31);
this->spriteOffset = Vec(-1, -1);
this->spriteSize = Vec(36, 36);
this->spriteImage = Image::load("res/ComponentLibrary/PJ3410.png");
@@ -131,23 +149,31 @@ struct ValueLight : Light {
float *value;
};

struct RedValueLight : ValueLight {
template <int COLOR>
struct ColorValueLight : ValueLight {
void step() {
float v = sqrtBipolar(getf(value));
color = nvgLerpRGBA(SCHEME_BLACK, SCHEME_RED, v);
color = nvgLerpRGBA(colors[COLOR_BLACK], colors[COLOR], v);
}
};

struct GreenRedPolarityLight : ValueLight {
typedef ColorValueLight<COLOR_RED> RedValueLight;
typedef ColorValueLight<COLOR_YELLOW> YellowValueLight;
typedef ColorValueLight<COLOR_GREEN> GreenValueLight;

template <int COLOR_POS, int COLOR_NEG>
struct PolarityLight : ValueLight {
void step() {
float v = sqrtBipolar(getf(value));
if (v >= 0.0)
color = nvgLerpRGBA(SCHEME_BLACK, SCHEME_GREEN, v);
color = nvgLerpRGBA(colors[COLOR_BLACK], colors[COLOR_POS], v);
else
color = nvgLerpRGBA(SCHEME_BLACK, SCHEME_RED, -v);
color = nvgLerpRGBA(colors[COLOR_BLACK], colors[COLOR_NEG], -v);
}
};

typedef PolarityLight<COLOR_GREEN, COLOR_RED> GreenRedPolarityLight;

template <typename BASE>
struct LargeLight : BASE {
LargeLight() {
@@ -197,13 +223,13 @@ struct SilverScrew : Screw {
struct LightPanel : Panel {
LightPanel() {
backgroundColor = nvgRGB(0xe8, 0xe8, 0xe8);
borderColor = nvgRGB(0xac, 0xac, 0xac);
borderColor = nvgRGB(0xa1, 0xa1, 0xa1);
}
};

struct DarkPanel : Panel {
DarkPanel() {
backgroundColor = nvgRGB(0x0f, 0x0f, 0x0f);
backgroundColor = nvgRGB(0x17, 0x17, 0x17);
borderColor = nvgRGB(0x5e, 0x5e, 0x5e);
}
};


+ 1
- 2
include/gui.hpp View File

@@ -13,7 +13,6 @@ void guiCursorUnlock();
const char *guiSaveDialog(const char *filters, const char *filename);
const char *guiOpenDialog(const char *filters, const char *filename);

// TODO This should probably go in another file, like resources.hpp?
void drawSVG(NVGcontext *vg, NSVGimage *svg);
extern NVGcontext *gVg;

} // namespace rack

+ 12
- 0
include/math.hpp View File

@@ -61,6 +61,12 @@ inline float sqrtBipolar(float x) {
return x >= 0.0 ? sqrtf(x) : -sqrtf(-x);
}

/** This is pretty much a scaled sinh */
inline float exponentialBipolar(float b, float x) {
const float a = b - 1.0 / b;
return (powf(b, x) - powf(b, -x)) / a;
}

inline float sincf(float x) {
if (x == 0.0)
return 1.0;
@@ -145,6 +151,12 @@ struct Vec {
Vec round() {
return Vec(roundf(x), roundf(y));
}
bool isFinite() {
return isfinite(x) && isfinite(y);
}
bool isZero() {
return x == 0.0 && y == 0.0;
}
};




+ 45
- 2
include/widgets.hpp View File

@@ -43,7 +43,7 @@ struct SVG {


////////////////////
// base class and traits
// Base widget
////////////////////

/** A node in the 2D scene graph */
@@ -112,6 +112,22 @@ struct Widget {
virtual void onChange() {}
};

struct TransformWidget : Widget {
/** The transformation matrix */
float transform[6];
TransformWidget();
void reset();
void translate(Vec delta);
void rotate(float angle);
void scale(Vec s);
void draw(NVGcontext *vg);
};


////////////////////
// Trait widgets
////////////////////

/** Widget that does not respond to events */
struct TransparentWidget : virtual Widget {
Widget *onMouseDown(Vec pos, int button) {return NULL;}
@@ -157,6 +173,33 @@ struct SpriteWidget : virtual Widget {
void draw(NVGcontext *vg);
};

struct SVGWidget : virtual Widget {
std::shared_ptr<SVG> svg;
/** Sets the box size to the svg page */
void step();
void draw(NVGcontext *vg);
};

/** Caches a widget's draw() result to a framebuffer so it is called less frequently
When `dirty` is true, `scene` will be re-rendered on the next call to step().
Events are not passed to the underlying scene.
*/
struct FramebufferWidget : virtual Widget {
bool dirty = true;
/** The root object in the framebuffer scene
Its position is ignored for now, fixed at (0, 0)
The FramebufferWidget owns the pointer
*/
Widget *scene = NULL;
struct Internal;
Internal *internal;

FramebufferWidget();
~FramebufferWidget();
void step();
void draw(NVGcontext *vg);
};

struct QuantityWidget : virtual Widget {
float value = 0.0;
float minValue = 0.0;
@@ -179,7 +222,7 @@ struct QuantityWidget : virtual Widget {
};

////////////////////
// gui elements
// GUI widgets
////////////////////

struct Label : Widget {


+ 19
- 0
src/components.cpp View File

@@ -0,0 +1,19 @@
#include "components.hpp"


namespace rack {

const NVGcolor colors[NUM_COLORS] = {
nvgRGB(0x00, 0x00, 0x00),
nvgRGB(0xff, 0xff, 0xff),
nvgRGB(0xed, 0x2c, 0x24),
nvgRGB(0xf2, 0xb1, 0x20),
nvgRGB(0xf9, 0xdf, 0x1c),
nvgRGB(0x90, 0xc7, 0x3e),
nvgRGB(0x22, 0xe6, 0xef),
nvgRGB(0x29, 0xb2, 0xef),
nvgRGB(0xd5, 0x2b, 0xed),
};


} // namespace rack

+ 16
- 96
src/gui.cpp View File

@@ -7,9 +7,10 @@
#include "scene.hpp"

// Include implementations here
// By the way, please stop packaging your libraries like this. It's easiest to use a single source file (e.g. foo.c) and a single header (e.g. foo.h)
// By the way, please stop packaging your libraries like this. It's best to use a single source file (e.g. foo.c) and a single header (e.g. foo.h)
#define NANOVG_GL3_IMPLEMENTATION
#include "../ext/nanovg/src/nanovg_gl.h"
#include "../ext/nanovg/src/nanovg_gl_utils.h"
#define BLENDISH_IMPLEMENTATION
#include "../ext/oui/blendish.h"
#define NANOSVG_IMPLEMENTATION
@@ -23,8 +24,8 @@ extern "C" {
namespace rack {

static GLFWwindow *window = NULL;
static NVGcontext *vg = NULL;
static std::shared_ptr<Font> defaultFont;
NVGcontext *gVg = NULL;


void windowSizeCallback(GLFWwindow* window, int width, int height) {
@@ -160,16 +161,16 @@ void renderGui() {

// Update and render
glViewport(0, 0, width, height);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

nvgBeginFrame(vg, width, height, 1.0);
nvgBeginFrame(gVg, width, height, 1.0);

nvgSave(vg);
gScene->draw(vg);
nvgRestore(vg);
nvgSave(gVg);
gScene->draw(gVg);
nvgRestore(gVg);

nvgEndFrame(vg);
nvgEndFrame(gVg);
glfwSwapBuffers(window);
}

@@ -180,12 +181,10 @@ void guiInit() {
err = glfwInit();
assert(err);

// #ifndef WINDOWS
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// #endif
window = glfwCreateWindow(1000, 750, gApplicationName.c_str(), NULL, NULL);
assert(window);
glfwMakeContextCurrent(window);
@@ -210,8 +209,8 @@ void guiInit() {
glfwSetWindowSizeLimits(window, 240, 160, GLFW_DONT_CARE, GLFW_DONT_CARE);

// Set up NanoVG
vg = nvgCreateGL3(NVG_ANTIALIAS);
assert(vg);
gVg = nvgCreateGL3(NVG_ANTIALIAS);
assert(gVg);

// Set up Blendish
defaultFont = Font::load("res/DejaVuSans.ttf");
@@ -221,7 +220,7 @@ void guiInit() {

void guiDestroy() {
defaultFont.reset();
nvgDeleteGL3(vg);
nvgDeleteGL3(gVg);
glfwDestroyWindow(window);
glfwTerminate();
}
@@ -275,7 +274,7 @@ const char *guiOpenDialog(const char *filters, const char *filename) {
////////////////////

Font::Font(const std::string &filename) {
handle = nvgCreateFont(vg, filename.c_str(), filename.c_str());
handle = nvgCreateFont(gVg, filename.c_str(), filename.c_str());
if (handle >= 0) {
fprintf(stderr, "Loaded font %s\n", filename.c_str());
}
@@ -285,7 +284,7 @@ Font::Font(const std::string &filename) {
}

Font::~Font() {
// There is no NanoVG deleteFont() function, so do nothing
// There is no NanoVG deleteFont() function yet, so do nothing
}

std::shared_ptr<Font> Font::load(const std::string &filename) {
@@ -301,7 +300,7 @@ std::shared_ptr<Font> Font::load(const std::string &filename) {
////////////////////

Image::Image(const std::string &filename) {
handle = nvgCreateImage(vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
handle = nvgCreateImage(gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
if (handle > 0) {
fprintf(stderr, "Loaded image %s\n", filename.c_str());
}
@@ -312,7 +311,7 @@ Image::Image(const std::string &filename) {

Image::~Image() {
// TODO What if handle is invalid?
nvgDeleteImage(vg, handle);
nvgDeleteImage(gVg, handle);
}

std::shared_ptr<Image> Image::load(const std::string &filename) {
@@ -350,83 +349,4 @@ std::shared_ptr<SVG> SVG::load(const std::string &filename) {
}


////////////////////
// drawSVG
////////////////////

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);
}

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);

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

nvgSave(vg);
nvgGlobalAlpha(vg, shape->opacity);
nvgStrokeWidth(vg, shape->strokeWidth);
// strokeDashOffset, strokeDashArray, strokeDashCount not supported
// strokeLineJoin, strokeLineCap not 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");

nvgMoveTo(vg, path->pts[0], path->pts[1]);
for (int i = 1; i < path->npts; i += 3) {
float *p = &path->pts[2*i];
nvgBezierTo(vg, p[0], p[1], p[2], p[3], p[4], p[5]);
// nvgLineTo(vg, p[4], p[5]);
}

if (path->closed)
nvgClosePath(vg);


if (path->next)
nvgPathWinding(vg, NVG_HOLE);
}

// Fill shape
if (shape->fill.type) {
switch (shape->fill.type) {
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);
} break;
case NSVG_PAINT_LINEAR_GRADIENT: {
NSVGgradient *g = shape->fill.gradient;
// printf(" lin grad: %f\t%f\n", g->fx, g->fy);
} break;
}
nvgFill(vg);
}

// Stroke shape
if (shape->stroke.type) {
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);
} break;
case NSVG_PAINT_LINEAR_GRADIENT: {
NSVGgradient *g = shape->stroke.gradient;
// printf(" lin grad: %f\t%f\n", g->fx, g->fy);
} break;
}
nvgStroke(vg);
}

nvgRestore(vg);
}
}


} // namespace rack

+ 88
- 0
src/widgets/FramebufferWidget.cpp View File

@@ -0,0 +1,88 @@
#include "widgets.hpp"
#include "gui.hpp"
#include <GL/glew.h>
#include "../ext/nanovg/src/nanovg_gl.h"
#include "../ext/nanovg/src/nanovg_gl_utils.h"


namespace rack {


struct FramebufferWidget::Internal {
NVGLUframebuffer *fb = NULL;

~Internal() {
setFramebuffer(NULL);
}
void setFramebuffer(NVGLUframebuffer *fb) {
if (this->fb)
nvgluDeleteFramebuffer(this->fb);
this->fb = fb;
}
};

FramebufferWidget::FramebufferWidget() {
internal = new Internal();
}

FramebufferWidget::~FramebufferWidget() {
if (scene) {
delete scene;
}
delete internal;
}

/** A margin in pixels around the scene in the framebuffer */
static const int margin = 1;

void FramebufferWidget::step() {
if (!scene)
return;

scene->step();

// Render the scene to the framebuffer if dirty
if (dirty) {
assert(scene->box.size.isFinite());
int width = ceilf(scene->box.size.x) + 2*margin;
int height = ceilf(scene->box.size.y) + 2*margin;

internal->setFramebuffer(NULL);
NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, width, height, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
assert(fb);
internal->setFramebuffer(fb);

// TODO Support screens with pixelRatio != 1.0 (e.g. Retina) by using the actual size of the framebuffer, etc.
const float pixelRatio = 1.0;
nvgluBindFramebuffer(fb);
glViewport(0.0, 0.0, width, height);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
nvgBeginFrame(gVg, width, height, pixelRatio);

nvgTranslate(gVg, margin, margin);
scene->draw(gVg);

nvgEndFrame(gVg);
nvgluBindFramebuffer(NULL);

dirty = false;
}
}

void FramebufferWidget::draw(NVGcontext *vg) {
if (!internal->fb)
return;

// Draw framebuffer image
int width, height;
nvgImageSize(vg, internal->fb->image, &width, &height);
nvgBeginPath(vg);
nvgRect(vg, -margin, -margin, width, height);
NVGpaint paint = nvgImagePattern(vg, -margin, -margin, width, height, 0.0, internal->fb->image, 1.0);
nvgFillPaint(vg, paint);
nvgFill(vg);
}


} // namespace rack

+ 12
- 12
src/widgets/Light.cpp View File

@@ -17,18 +17,18 @@ void Light::draw(NVGcontext *vg) {
nvgStrokeColor(vg, colorOutline);
nvgStroke(vg);

// nvgGlobalCompositeOperation(vg, NVG_LIGHTER);
// NVGpaint paint;
// NVGcolor icol = color;
// icol.a = 0.2;
// NVGcolor ocol = color;
// ocol.a = 0.0;
// float oradius = radius + 20.0;
// paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol);
// nvgFillPaint(vg, paint);
// nvgBeginPath(vg);
// nvgRect(vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius);
// nvgFill(vg);
nvgGlobalCompositeOperation(vg, NVG_LIGHTER);
NVGpaint paint;
NVGcolor icol = color;
icol.a = 0.1;
NVGcolor ocol = color;
ocol.a = 0.0;
float oradius = radius + 30.0;
paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol);
nvgFillPaint(vg, paint);
nvgBeginPath(vg);
nvgRect(vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius);
nvgFill(vg);
}




+ 1
- 1
src/widgets/ModuleWidget.cpp View File

@@ -181,7 +181,7 @@ void ModuleWidget::onMouseDown(int button) {
menu->pushChild(menuLabel);

ResetParamsMenuItem *resetItem = new ResetParamsMenuItem();
resetItem->text = "Reset parameters";
resetItem->text = "Initialize parameters";
resetItem->moduleWidget = this;
menu->pushChild(resetItem);



+ 95
- 0
src/widgets/SVGWidget.cpp View File

@@ -0,0 +1,95 @@
#include "widgets.hpp"


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 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);

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

nvgSave(vg);
nvgGlobalAlpha(vg, shape->opacity);
nvgStrokeWidth(vg, shape->strokeWidth);
// strokeDashOffset, strokeDashArray, strokeDashCount not supported
// strokeLineJoin, strokeLineCap not 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");

nvgMoveTo(vg, path->pts[0], path->pts[1]);
for (int i = 1; i < path->npts; i += 3) {
float *p = &path->pts[2*i];
nvgBezierTo(vg, p[0], p[1], p[2], p[3], p[4], p[5]);
// nvgLineTo(vg, p[4], p[5]);
}

if (path->closed)
nvgClosePath(vg);


if (path->next)
nvgPathWinding(vg, NVG_HOLE);
}

// Fill shape
if (shape->fill.type) {
switch (shape->fill.type) {
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);
} break;
case NSVG_PAINT_LINEAR_GRADIENT: {
// NSVGgradient *g = shape->fill.gradient;
// printf(" lin grad: %f\t%f\n", g->fx, g->fy);
} break;
}
nvgFill(vg);
}

// Stroke shape
if (shape->stroke.type) {
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);
} break;
case NSVG_PAINT_LINEAR_GRADIENT: {
// NSVGgradient *g = shape->stroke.gradient;
// printf(" lin grad: %f\t%f\n", g->fx, g->fy);
} break;
}
nvgStroke(vg);
}

nvgRestore(vg);
}
}


void SVGWidget::step() {
// Automatically wrap box size to SVG page size
if (svg)
box.size = Vec(svg->handle->width, svg->handle->height);
else
box.size = Vec();
}

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


} // namespace rack

+ 40
- 0
src/widgets/TransformWidget.cpp View File

@@ -0,0 +1,40 @@
#include "scene.hpp"


namespace rack {


TransformWidget::TransformWidget() {
reset();
}

void TransformWidget::reset() {
nvgTransformIdentity(transform);
}

void TransformWidget::translate(Vec delta) {
float t[6];
nvgTransformTranslate(t, delta.x, delta.y);
nvgTransformPremultiply(transform, t);
}

void TransformWidget::rotate(float angle) {
float t[6];
nvgTransformRotate(t, angle);
nvgTransformPremultiply(transform, t);
}

void TransformWidget::scale(Vec s) {
float t[6];
nvgTransformScale(t, s.x, s.y);
nvgTransformPremultiply(transform, t);
}

void TransformWidget::draw(NVGcontext *vg) {
// No need to save the state because that is done in the parent
nvgTransform(vg, transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]);
Widget::draw(vg);
}


} // namespace rack

+ 1
- 1
src/widgets/WireWidget.cpp View File

@@ -32,7 +32,7 @@ static void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, NVGcolor color, float t
// Wire
if (opacity > 0.0) {
nvgSave(vg);
nvgGlobalAlpha(vg, opacity);
nvgGlobalAlpha(vg, powf(opacity, 1.5));

float dist = pos1.minus(pos2).norm();
Vec slump;


Loading…
Cancel
Save