@@ -30,9 +30,6 @@ CFLAGS += -DNOC_FILE_DIALOG_OSX | |||
CXXFLAGS += -DAPPLE -stdlib=libc++ -I$(HOME)/local/include | |||
LDFLAGS += -stdlib=libc++ -L$(HOME)/local/lib -lpthread -lglew -lglfw3 -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo -ldl -ljansson -lportaudio -lportmidi -lsamplerate | |||
TARGET = Rack | |||
Rack.app: $(TARGET) | |||
./bundle.sh | |||
endif | |||
# Windows | |||
@@ -52,41 +49,13 @@ LDFLAGS += \ | |||
-L$(HOME)/pkg/portaudio-r1891-build/lib/x64/ReleaseMinDependency -lportaudio_x64 \ | |||
-Wl,--export-all-symbols,--out-implib,libRack.a -mwindows | |||
TARGET = Rack.exe | |||
# OBJECTS = Rack.res | |||
%.res: %.rc | |||
windres $^ -O coff -o $@ | |||
endif | |||
OBJECTS = Rack.res | |||
all: $(TARGET) | |||
dist: $(TARGET) | |||
# Rack | |||
mkdir -p dist/Rack | |||
cp LICENSE* dist/Rack/ | |||
ifeq ($(ARCH), linux) | |||
cp Rack dist/Rack/ | |||
endif | |||
ifeq ($(ARCH), apple) | |||
./bundle.sh | |||
cp -R Rack.app dist/Rack/ | |||
endif | |||
ifeq ($(ARCH), windows) | |||
cp Rack.exe dist/Rack/ | |||
./copy_dlls.sh | |||
cp *.dll dist/Rack/ | |||
%.res: %.rc | |||
windres $^ -O coff -o $@ | |||
endif | |||
cp -R res dist/Rack/ | |||
mkdir -p dist/Rack/plugins | |||
# Fundamental | |||
$(MAKE) -C plugins/Fundamental dist | |||
cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/ | |||
# zip | |||
cd dist && zip -5 -r Rack.zip Rack | |||
clean: | |||
rm -rfv build $(TARGET) dist | |||
include Makefile.inc |
@@ -0,0 +1 @@ | |||
GLFW_ICON ICON res/icon.ico |
@@ -0,0 +1,97 @@ | |||
#pragma once | |||
#include "scene.hpp" | |||
namespace rack { | |||
//////////////////// | |||
// knobs | |||
//////////////////// | |||
struct KnobDavies1900h : SpriteKnob { | |||
KnobDavies1900h() { | |||
box.size = Vec(36, 36); | |||
spriteOffset = Vec(-8, -8); | |||
spriteSize = Vec(64, 64); | |||
minIndex = 44; | |||
maxIndex = -46; | |||
spriteCount = 120; | |||
} | |||
}; | |||
struct KnobDavies1900hWhite : KnobDavies1900h { | |||
KnobDavies1900hWhite() { | |||
spriteImage = Image::load("res/ComponentLibrary/Davies1900hWhite.png"); | |||
} | |||
}; | |||
struct KnobDavies1900hBlack : KnobDavies1900h { | |||
KnobDavies1900hBlack() { | |||
spriteImage = Image::load("res/ComponentLibrary/Davies1900hBlack.png"); | |||
} | |||
}; | |||
struct KnobDavies1900hRed : KnobDavies1900h { | |||
KnobDavies1900hRed() { | |||
spriteImage = Image::load("res/ComponentLibrary/Davies1900hRed.png"); | |||
} | |||
}; | |||
//////////////////// | |||
// ports | |||
//////////////////// | |||
struct PJ301M : SpriteWidget { | |||
PJ301M() { | |||
box.size = Vec(24, 24); | |||
spriteOffset = Vec(-10, -10); | |||
spriteSize = Vec(48, 48); | |||
spriteImage = Image::load("res/ComponentLibrary/PJ301M.png"); | |||
} | |||
}; | |||
struct InputPortPJ301M : InputPort, PJ301M {}; | |||
struct OutputPortPJ301M: OutputPort, PJ301M {}; | |||
struct PJ3410 : SpriteWidget { | |||
PJ3410() { | |||
box.size = Vec(31, 31); | |||
spriteOffset = Vec(-9, -9); | |||
spriteSize = Vec(54, 54); | |||
spriteImage = Image::load("res/ComponentLibrary/PJ3410.png"); | |||
} | |||
}; | |||
struct InputPortPJ3410 : InputPort, PJ3410 {}; | |||
struct OutputPortPJ3410: OutputPort, PJ3410 {}; | |||
struct CL1362 : SpriteWidget { | |||
CL1362() { | |||
box.size = Vec(33, 29); | |||
spriteOffset = Vec(-10, -10); | |||
spriteSize = Vec(57, 54); | |||
spriteImage = Image::load("res/ComponentLibrary/CL1362.png"); | |||
} | |||
}; | |||
struct InputPortCL1362 : InputPort, CL1362 {}; | |||
struct OutputPortCL1362 : OutputPort, CL1362 {}; | |||
//////////////////// | |||
// panels | |||
//////////////////// | |||
struct LightPanel : Panel { | |||
LightPanel() { | |||
backgroundColor = nvgRGB(0xe8, 0xe8, 0xe8); | |||
borderColor = nvgRGB(0xac, 0xac, 0xac); | |||
} | |||
}; | |||
struct DarkPanel : Panel { | |||
DarkPanel() { | |||
backgroundColor = nvgRGB(0x0f, 0x0f, 0x0f); | |||
borderColor = nvgRGB(0x5e, 0x5e, 0x5e); | |||
} | |||
}; | |||
} // namespace rack |
@@ -13,5 +13,7 @@ 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); | |||
} // namespace rack |
@@ -2,6 +2,7 @@ | |||
#include "plugin.hpp" | |||
#include "engine.hpp" | |||
#include "gui.hpp" | |||
#include "components.hpp" | |||
namespace rack { | |||
@@ -11,14 +12,6 @@ namespace rack { | |||
// helpers | |||
//////////////////// | |||
inline | |||
Plugin *createPlugin(std::string slug, std::string name) { | |||
Plugin *plugin = new Plugin(); | |||
plugin->slug = slug; | |||
plugin->name = name; | |||
return plugin; | |||
} | |||
template <class TModuleWidget> | |||
Model *createModel(Plugin *plugin, std::string slug, std::string name) { | |||
struct TModel : Model { | |||
@@ -93,8 +93,9 @@ struct RackWidget : OpaqueWidget { | |||
void onMouseDown(int button); | |||
}; | |||
struct ModulePanel : TransparentWidget { | |||
struct Panel : TransparentWidget { | |||
NVGcolor backgroundColor; | |||
NVGcolor borderColor; | |||
std::shared_ptr<Image> backgroundImage; | |||
void draw(NVGcontext *vg); | |||
}; | |||
@@ -109,7 +110,7 @@ struct Light : TransparentWidget, SpriteWidget { | |||
}; | |||
// If you don't add these to your ModuleWidget, it will fall out of the RackWidget | |||
struct Screw : TransparentWidget, SpriteWidget { | |||
struct Screw : TransparentWidget { | |||
Screw(); | |||
}; | |||
@@ -123,14 +124,17 @@ struct ParamWidget : OpaqueWidget, QuantityWidget { | |||
void onChange(); | |||
}; | |||
struct Knob : ParamWidget, SpriteWidget { | |||
int minIndex, maxIndex, spriteCount; | |||
void step(); | |||
struct Knob : ParamWidget { | |||
void onDragStart(); | |||
void onDragMove(Vec mouseRel); | |||
void onDragEnd(); | |||
}; | |||
struct SpriteKnob : Knob, SpriteWidget { | |||
int minIndex, maxIndex, spriteCount; | |||
void step(); | |||
}; | |||
struct Switch : ParamWidget, SpriteWidget { | |||
}; | |||
@@ -212,47 +216,9 @@ struct RackScene : Scene { | |||
RackScene(); | |||
void step(); | |||
void draw(NVGcontext *vg); | |||
}; | |||
//////////////////// | |||
// Component Library | |||
//////////////////// | |||
struct PJ301M : SpriteWidget { | |||
PJ301M() { | |||
box.size = Vec(24, 24); | |||
spriteOffset = Vec(-10, -10); | |||
spriteSize = Vec(48, 48); | |||
spriteImage = Image::load("res/ComponentLibrary/PJ301M.png"); | |||
} | |||
}; | |||
struct InputPortPJ301M : InputPort, PJ301M {}; | |||
struct OutputPortPJ301M: OutputPort, PJ301M {}; | |||
struct PJ3410 : SpriteWidget { | |||
PJ3410() { | |||
box.size = Vec(31, 31); | |||
spriteOffset = Vec(-9, -9); | |||
spriteSize = Vec(54, 54); | |||
spriteImage = Image::load("res/ComponentLibrary/PJ3410.png"); | |||
} | |||
}; | |||
struct InputPortPJ3410 : InputPort, PJ3410 {}; | |||
struct OutputPortPJ3410: OutputPort, PJ3410 {}; | |||
struct CL1362 : SpriteWidget { | |||
CL1362() { | |||
box.size = Vec(33, 29); | |||
spriteOffset = Vec(-10, -10); | |||
spriteSize = Vec(57, 54); | |||
spriteImage = Image::load("res/ComponentLibrary/CL1362.png"); | |||
} | |||
}; | |||
struct InputPortCL1362 : InputPort, CL1362 {}; | |||
struct OutputPortCL1362 : OutputPort, CL1362 {}; | |||
//////////////////// | |||
// globals | |||
//////////////////// | |||
@@ -35,7 +35,7 @@ struct Image { | |||
}; | |||
struct SVG { | |||
NSVGimage *image; | |||
NSVGimage *handle; | |||
SVG(const std::string &filename); | |||
~SVG(); | |||
static std::shared_ptr<SVG> load(const std::string &filename); | |||
@@ -46,7 +46,7 @@ struct AudioInterface : Module { | |||
SampleRateConverter<2> outputSrc; | |||
// in rack's sample rate | |||
DoubleRingBuffer<Frame<2>, 32> inputBuffer; | |||
DoubleRingBuffer<Frame<2>, 16> inputBuffer; | |||
DoubleRingBuffer<Frame<2>, (1<<15)> outputBuffer; | |||
// in device's sample rate | |||
DoubleRingBuffer<Frame<2>, (1<<15)> inputSrcBuffer; | |||
@@ -121,7 +121,7 @@ void AudioInterface::step() { | |||
err = Pa_ReadStream(stream, (float*) buf, blockSize); | |||
if (err) { | |||
// Ignore buffer underflows | |||
if (err != paInputOverflowed) { | |||
if (err == paInputOverflowed) { | |||
fprintf(stderr, "Audio input buffer underflow\n"); | |||
} | |||
} | |||
@@ -143,7 +143,7 @@ void AudioInterface::step() { | |||
inputSrcBuffer.startIncr(blockSize); | |||
if (err) { | |||
// Ignore buffer underflows | |||
if (err != paOutputUnderflowed) { | |||
if (err == paOutputUnderflowed) { | |||
fprintf(stderr, "Audio output buffer underflow\n"); | |||
} | |||
} | |||
@@ -308,7 +308,8 @@ struct SampleRateChoice : ChoiceButton { | |||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | |||
const float sampleRates[6] = {44100, 48000, 88200, 96000, 176400, 192000}; | |||
for (int i = 0; i < 6; i++) { | |||
int sampleRatesLen = sizeof(sampleRates) / sizeof(sampleRates[0]); | |||
for (int i = 0; i < sampleRatesLen; i++) { | |||
SampleRateItem *item = new SampleRateItem(); | |||
item->audioInterface = audioInterface; | |||
item->sampleRate = sampleRates[i]; | |||
@@ -340,8 +341,9 @@ struct BlockSizeChoice : ChoiceButton { | |||
Menu *menu = new Menu(); | |||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | |||
const int blockSizes[6] = {128, 256, 512, 1024, 2048, 4096}; | |||
for (int i = 0; i < 6; i++) { | |||
const int blockSizes[] = {64, 128, 256, 512, 1024, 2048, 4096}; | |||
int blockSizesLen = sizeof(blockSizes) / sizeof(blockSizes[0]); | |||
for (int i = 0; i < blockSizesLen; i++) { | |||
BlockSizeItem *item = new BlockSizeItem(); | |||
item->audioInterface = audioInterface; | |||
item->blockSize = blockSizes[i]; | |||
@@ -362,24 +364,14 @@ AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface() | |||
box.size = Vec(15*8, 380); | |||
{ | |||
ModulePanel *panel = new ModulePanel(); | |||
Panel *panel = new LightPanel(); | |||
panel->box.size = box.size; | |||
panel->backgroundColor = nvgRGBf(0.90, 0.90, 0.90); | |||
// panel->imageFilename = ""; | |||
addChild(panel); | |||
} | |||
float margin = 5; | |||
float yPos = margin; | |||
{ | |||
Label *label = new Label(); | |||
label->box.pos = Vec(margin, yPos); | |||
label->text = "Audio Interface"; | |||
addChild(label); | |||
yPos += label->box.size.y + margin; | |||
} | |||
{ | |||
Label *label = new Label(); | |||
label->box.pos = Vec(margin, yPos); | |||
@@ -225,10 +225,8 @@ MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) { | |||
box.size = Vec(15*8, 380); | |||
{ | |||
ModulePanel *panel = new ModulePanel(); | |||
Panel *panel = new LightPanel(); | |||
panel->box.size = box.size; | |||
panel->backgroundColor = nvgRGBf(0.90, 0.90, 0.90); | |||
// panel->imageFilename = ""; | |||
addChild(panel); | |||
} | |||
@@ -1,9 +1,6 @@ | |||
#include "core.hpp" | |||
using namespace rack; | |||
struct CorePlugin : Plugin { | |||
CorePlugin() { | |||
slug = "Core"; | |||
@@ -129,9 +129,9 @@ static void engineRun() { | |||
} | |||
} | |||
auto end = std::chrono::high_resolution_clock::now(); | |||
auto duration = std::chrono::nanoseconds((long) (0.9 * 1e9 * stepSize / gSampleRate)) - (end - start); | |||
auto duration = std::chrono::nanoseconds((long) (0.5 * 1e9 * stepSize / gSampleRate)) - (end - start); | |||
// Avoid pegging the CPU at 100% when there are no "blocking" modules like AudioInterface, but still step audio at a reasonable rate | |||
std::this_thread::sleep_for(duration); | |||
// std::this_thread::sleep_for(duration); | |||
} | |||
} | |||
@@ -314,8 +314,8 @@ std::shared_ptr<Image> Image::load(const std::string &filename) { | |||
//////////////////// | |||
SVG::SVG(const std::string &filename) { | |||
image = nsvgParseFromFile(filename.c_str(), "px", 96.0); | |||
if (image) { | |||
handle = nsvgParseFromFile(filename.c_str(), "px", 96.0); | |||
if (handle) { | |||
fprintf(stderr, "Loaded SVG %s\n", filename.c_str()); | |||
} | |||
else { | |||
@@ -324,7 +324,7 @@ SVG::SVG(const std::string &filename) { | |||
} | |||
SVG::~SVG() { | |||
nsvgDelete(image); | |||
nsvgDelete(handle); | |||
} | |||
std::shared_ptr<SVG> SVG::load(const std::string &filename) { | |||
@@ -336,4 +336,83 @@ 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 |
@@ -20,7 +20,7 @@ int main() { | |||
assert(success); | |||
CFRelease(bundleURL); | |||
chdir(dirname(path)); | |||
// chdir(dirname(path)); | |||
} | |||
#endif | |||
@@ -4,7 +4,7 @@ | |||
namespace rack { | |||
std::string gApplicationName = "VCV Rack"; | |||
std::string gApplicationVersion = "v0.1.0 alpha"; | |||
std::string gApplicationVersion = "v0.2.0 alpha"; | |||
RackWidget *gRackWidget = NULL; | |||
@@ -7,10 +7,6 @@ namespace rack { | |||
#define KNOB_SENSITIVITY 0.001 | |||
void Knob::step() { | |||
index = eucmod((int) roundf(mapf(value, minValue, maxValue, minIndex, maxIndex)), spriteCount); | |||
} | |||
void Knob::onDragStart() { | |||
guiCursorLock(); | |||
} | |||
@@ -3,10 +3,9 @@ | |||
namespace rack { | |||
void ModulePanel::draw(NVGcontext *vg) { | |||
void Panel::draw(NVGcontext *vg) { | |||
nvgBeginPath(vg); | |||
nvgRect(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); | |||
NVGpaint paint; | |||
// Background color | |||
nvgFillColor(vg, backgroundColor); | |||
@@ -16,10 +15,15 @@ void ModulePanel::draw(NVGcontext *vg) { | |||
if (backgroundImage) { | |||
int width, height; | |||
nvgImageSize(vg, backgroundImage->handle, &width, &height); | |||
paint = nvgImagePattern(vg, box.pos.x, box.pos.y, width, height, 0.0, backgroundImage->handle, 1.0); | |||
NVGpaint paint = nvgImagePattern(vg, box.pos.x, box.pos.y, width, height, 0.0, backgroundImage->handle, 1.0); | |||
nvgFillPaint(vg, paint); | |||
nvgFill(vg); | |||
} | |||
// Border color | |||
nvgStrokeColor(vg, borderColor); | |||
nvgStrokeWidth(vg, 0.5); | |||
nvgStroke(vg); | |||
} | |||
} // namespace rack |
@@ -1,4 +1,5 @@ | |||
#include "scene.hpp" | |||
#include "gui.hpp" | |||
namespace rack { | |||
@@ -24,5 +25,23 @@ void RackScene::step() { | |||
Scene::step(); | |||
} | |||
void RackScene::draw(NVGcontext *vg) { | |||
Scene::draw(vg); | |||
// // Draw custom stuff here | |||
// static std::shared_ptr<SVG> svg; | |||
// if (!svg) | |||
// svg = SVG::load("res/ComponentLibrary/CL1362.svg"); | |||
// for (float y = 0.0; y < 1000.0; y += 200.0) | |||
// for (float x = 0.0; x < 1000.0; x += 200.0) { | |||
// nvgSave(vg); | |||
// nvgTranslate(vg, x, y); | |||
// drawSVG(vg, svg->handle); | |||
// nvgRestore(vg); | |||
// } | |||
} | |||
} // namespace rack |
@@ -288,23 +288,18 @@ void RackWidget::step() { | |||
} | |||
void RackWidget::draw(NVGcontext *vg) { | |||
// Draw background | |||
nvgBeginPath(vg); | |||
nvgRect(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); | |||
NVGpaint paint; | |||
{ | |||
// int imageId = loadImage("res/background.png"); | |||
// int imageWidth, imageHeight; | |||
// nvgImageSize(vg, imageId, &imageWidth, &imageHeight); | |||
// paint = nvgImagePattern(vg, box.pos.x, box.pos.y, imageWidth, imageHeight, 0.0, imageId, 1.0); | |||
// nvgFillPaint(vg, paint); | |||
nvgFillColor(vg, nvgRGBf(0.25, 0.25, 0.25)); | |||
nvgFill(vg); | |||
} | |||
// Background color | |||
nvgFillColor(vg, nvgRGBf(0.2, 0.2, 0.2)); | |||
nvgFill(vg); | |||
// Rails image | |||
{ | |||
int imageWidth, imageHeight; | |||
nvgImageSize(vg, railsImage->handle, &imageWidth, &imageHeight); | |||
paint = nvgImagePattern(vg, box.pos.x, box.pos.y, imageWidth, imageHeight, 0.0, railsImage->handle, 1.0); | |||
NVGpaint paint = nvgImagePattern(vg, box.pos.x, box.pos.y, imageWidth, imageHeight, 0.0, railsImage->handle, 1.0); | |||
nvgFillPaint(vg, paint); | |||
nvgFill(vg); | |||
} | |||
@@ -4,12 +4,12 @@ | |||
namespace rack { | |||
Screw::Screw() { | |||
box.size = Vec(15, 15); | |||
spriteOffset = Vec(-7, -7); | |||
spriteSize = Vec(29, 29); | |||
spriteImage = Image::load("res/screw.png"); | |||
// box.size = Vec(15, 15); | |||
// spriteOffset = Vec(-7, -7); | |||
// spriteSize = Vec(29, 29); | |||
// spriteImage = Image::load("res/screw.png"); | |||
index = randomu32() % 5; | |||
// index = randomu32() % 5; | |||
} | |||
@@ -0,0 +1,10 @@ | |||
#include "scene.hpp" | |||
namespace rack { | |||
void SpriteKnob::step() { | |||
index = eucmod((int) roundf(mapf(value, minValue, maxValue, minIndex, maxIndex)), spriteCount); | |||
} | |||
} // namespace rack |
@@ -4,10 +4,28 @@ | |||
namespace rack { | |||
void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, float tension, NVGcolor color, float opacity) { | |||
NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.08); | |||
static void drawPlug(NVGcontext *vg, Vec pos, NVGcolor color) { | |||
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos.x, pos.y, 10.5); | |||
nvgFillColor(vg, colorOutline); | |||
nvgFill(vg); | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos.x, pos.y, 9.5); | |||
nvgFillColor(vg, color); | |||
nvgFill(vg); | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos.x, pos.y, 5.5); | |||
nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0)); | |||
nvgFill(vg); | |||
} | |||
static void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, NVGcolor color, float tension, float opacity) { | |||
NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.08); | |||
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | |||
// Wire | |||
if (opacity > 0.0) { | |||
@@ -35,68 +53,36 @@ void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, float tension, NVGcolor color, | |||
nvgMoveTo(vg, pos1.x, pos1.y); | |||
nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | |||
nvgStrokeColor(vg, colorOutline); | |||
nvgStrokeWidth(vg, 6); | |||
nvgStrokeWidth(vg, 5); | |||
nvgStroke(vg); | |||
// Wire solid | |||
nvgStrokeColor(vg, color); | |||
nvgStrokeWidth(vg, 4); | |||
nvgStrokeWidth(vg, 3); | |||
nvgStroke(vg); | |||
nvgRestore(vg); | |||
} | |||
// First plug | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos1.x, pos1.y, 21/2.0); | |||
nvgFillColor(vg, colorOutline); | |||
nvgFill(vg); | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos1.x, pos1.y, 19/2.0); | |||
nvgFillColor(vg, color); | |||
nvgFill(vg); | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos1.x, pos1.y, 11/2.0); | |||
nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0)); | |||
nvgFill(vg); | |||
// Second plug | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos2.x, pos2.y, 21/2.0); | |||
nvgFillColor(vg, colorOutline); | |||
nvgFill(vg); | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos2.x, pos2.y, 19/2.0); | |||
nvgFillColor(vg, color); | |||
nvgFill(vg); | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos2.x, pos2.y, 11/2.0); | |||
nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0)); | |||
nvgFill(vg); | |||
} | |||
static NVGcolor wireColors[8] = { | |||
nvgRGB(0x50, 0x50, 0x50), | |||
nvgRGB(0xac, 0x41, 0x42), | |||
nvgRGB(0x90, 0xa9, 0x59), | |||
nvgRGB(0xf4, 0xbf, 0x75), | |||
nvgRGB(0x6a, 0x9f, 0xb5), | |||
nvgRGB(0xaa, 0x75, 0x9f), | |||
nvgRGB(0x75, 0xb5, 0xaa), | |||
nvgRGB(0xf5, 0xf5, 0xf5), | |||
nvgRGB(0xc9, 0xb7, 0x0e), // yellow | |||
nvgRGB(0xc9, 0x18, 0x47), // red | |||
nvgRGB(0x0c, 0x8e, 0x15), // green | |||
nvgRGB(0x09, 0x86, 0xad), // blue | |||
nvgRGB(0x44, 0x44, 0x44), // black | |||
nvgRGB(0x66, 0x66, 0x66), // gray | |||
nvgRGB(0x88, 0x88, 0x88), // light gray | |||
nvgRGB(0xaa, 0xaa, 0xaa), // white | |||
}; | |||
static int wireColorId = 1; | |||
static int nextWireColorId = 1; | |||
WireWidget::WireWidget() { | |||
wireColorId = (wireColorId + 1) % 8; | |||
color = wireColors[wireColorId]; | |||
color = wireColors[nextWireColorId]; | |||
nextWireColorId = (nextWireColorId + 1) % 8; | |||
} | |||
WireWidget::~WireWidget() { | |||
@@ -152,8 +138,11 @@ void WireWidget::draw(NVGcontext *vg) { | |||
outputPos = outputPos.minus(absolutePos); | |||
inputPos = inputPos.minus(absolutePos); | |||
drawWire(vg, outputPos, inputPos, tension, color, opacity); | |||
drawWire(vg, outputPos, inputPos, color, tension, opacity); | |||
drawPlug(vg, outputPos, color); | |||
drawPlug(vg, inputPos, color); | |||
} | |||
} // namespace rack |