| @@ -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 | |||