| @@ -30,9 +30,6 @@ CFLAGS += -DNOC_FILE_DIALOG_OSX | |||||
| CXXFLAGS += -DAPPLE -stdlib=libc++ -I$(HOME)/local/include | 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 | 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 | TARGET = Rack | ||||
| Rack.app: $(TARGET) | |||||
| ./bundle.sh | |||||
| endif | endif | ||||
| # Windows | # Windows | ||||
| @@ -52,41 +49,13 @@ LDFLAGS += \ | |||||
| -L$(HOME)/pkg/portaudio-r1891-build/lib/x64/ReleaseMinDependency -lportaudio_x64 \ | -L$(HOME)/pkg/portaudio-r1891-build/lib/x64/ReleaseMinDependency -lportaudio_x64 \ | ||||
| -Wl,--export-all-symbols,--out-implib,libRack.a -mwindows | -Wl,--export-all-symbols,--out-implib,libRack.a -mwindows | ||||
| TARGET = Rack.exe | TARGET = Rack.exe | ||||
| # OBJECTS = Rack.res | |||||
| %.res: %.rc | |||||
| windres $^ -O coff -o $@ | |||||
| endif | |||||
| OBJECTS = Rack.res | |||||
| all: $(TARGET) | 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 | 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 | 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 *guiSaveDialog(const char *filters, const char *filename); | ||||
| const char *guiOpenDialog(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 | } // namespace rack | ||||
| @@ -2,6 +2,7 @@ | |||||
| #include "plugin.hpp" | #include "plugin.hpp" | ||||
| #include "engine.hpp" | #include "engine.hpp" | ||||
| #include "gui.hpp" | #include "gui.hpp" | ||||
| #include "components.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| @@ -11,14 +12,6 @@ namespace rack { | |||||
| // helpers | // 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> | template <class TModuleWidget> | ||||
| Model *createModel(Plugin *plugin, std::string slug, std::string name) { | Model *createModel(Plugin *plugin, std::string slug, std::string name) { | ||||
| struct TModel : Model { | struct TModel : Model { | ||||
| @@ -93,8 +93,9 @@ struct RackWidget : OpaqueWidget { | |||||
| void onMouseDown(int button); | void onMouseDown(int button); | ||||
| }; | }; | ||||
| struct ModulePanel : TransparentWidget { | |||||
| struct Panel : TransparentWidget { | |||||
| NVGcolor backgroundColor; | NVGcolor backgroundColor; | ||||
| NVGcolor borderColor; | |||||
| std::shared_ptr<Image> backgroundImage; | std::shared_ptr<Image> backgroundImage; | ||||
| void draw(NVGcontext *vg); | 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 | // If you don't add these to your ModuleWidget, it will fall out of the RackWidget | ||||
| struct Screw : TransparentWidget, SpriteWidget { | |||||
| struct Screw : TransparentWidget { | |||||
| Screw(); | Screw(); | ||||
| }; | }; | ||||
| @@ -123,14 +124,17 @@ struct ParamWidget : OpaqueWidget, QuantityWidget { | |||||
| void onChange(); | void onChange(); | ||||
| }; | }; | ||||
| struct Knob : ParamWidget, SpriteWidget { | |||||
| int minIndex, maxIndex, spriteCount; | |||||
| void step(); | |||||
| struct Knob : ParamWidget { | |||||
| void onDragStart(); | void onDragStart(); | ||||
| void onDragMove(Vec mouseRel); | void onDragMove(Vec mouseRel); | ||||
| void onDragEnd(); | void onDragEnd(); | ||||
| }; | }; | ||||
| struct SpriteKnob : Knob, SpriteWidget { | |||||
| int minIndex, maxIndex, spriteCount; | |||||
| void step(); | |||||
| }; | |||||
| struct Switch : ParamWidget, SpriteWidget { | struct Switch : ParamWidget, SpriteWidget { | ||||
| }; | }; | ||||
| @@ -212,47 +216,9 @@ struct RackScene : Scene { | |||||
| RackScene(); | RackScene(); | ||||
| void step(); | 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 | // globals | ||||
| //////////////////// | //////////////////// | ||||
| @@ -35,7 +35,7 @@ struct Image { | |||||
| }; | }; | ||||
| struct SVG { | struct SVG { | ||||
| NSVGimage *image; | |||||
| NSVGimage *handle; | |||||
| SVG(const std::string &filename); | SVG(const std::string &filename); | ||||
| ~SVG(); | ~SVG(); | ||||
| static std::shared_ptr<SVG> load(const std::string &filename); | static std::shared_ptr<SVG> load(const std::string &filename); | ||||
| @@ -46,7 +46,7 @@ struct AudioInterface : Module { | |||||
| SampleRateConverter<2> outputSrc; | SampleRateConverter<2> outputSrc; | ||||
| // in rack's sample rate | // in rack's sample rate | ||||
| DoubleRingBuffer<Frame<2>, 32> inputBuffer; | |||||
| DoubleRingBuffer<Frame<2>, 16> inputBuffer; | |||||
| DoubleRingBuffer<Frame<2>, (1<<15)> outputBuffer; | DoubleRingBuffer<Frame<2>, (1<<15)> outputBuffer; | ||||
| // in device's sample rate | // in device's sample rate | ||||
| DoubleRingBuffer<Frame<2>, (1<<15)> inputSrcBuffer; | DoubleRingBuffer<Frame<2>, (1<<15)> inputSrcBuffer; | ||||
| @@ -121,7 +121,7 @@ void AudioInterface::step() { | |||||
| err = Pa_ReadStream(stream, (float*) buf, blockSize); | err = Pa_ReadStream(stream, (float*) buf, blockSize); | ||||
| if (err) { | if (err) { | ||||
| // Ignore buffer underflows | // Ignore buffer underflows | ||||
| if (err != paInputOverflowed) { | |||||
| if (err == paInputOverflowed) { | |||||
| fprintf(stderr, "Audio input buffer underflow\n"); | fprintf(stderr, "Audio input buffer underflow\n"); | ||||
| } | } | ||||
| } | } | ||||
| @@ -143,7 +143,7 @@ void AudioInterface::step() { | |||||
| inputSrcBuffer.startIncr(blockSize); | inputSrcBuffer.startIncr(blockSize); | ||||
| if (err) { | if (err) { | ||||
| // Ignore buffer underflows | // Ignore buffer underflows | ||||
| if (err != paOutputUnderflowed) { | |||||
| if (err == paOutputUnderflowed) { | |||||
| fprintf(stderr, "Audio output buffer underflow\n"); | fprintf(stderr, "Audio output buffer underflow\n"); | ||||
| } | } | ||||
| } | } | ||||
| @@ -308,7 +308,8 @@ struct SampleRateChoice : ChoiceButton { | |||||
| menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | ||||
| const float sampleRates[6] = {44100, 48000, 88200, 96000, 176400, 192000}; | 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(); | SampleRateItem *item = new SampleRateItem(); | ||||
| item->audioInterface = audioInterface; | item->audioInterface = audioInterface; | ||||
| item->sampleRate = sampleRates[i]; | item->sampleRate = sampleRates[i]; | ||||
| @@ -340,8 +341,9 @@ struct BlockSizeChoice : ChoiceButton { | |||||
| Menu *menu = new Menu(); | Menu *menu = new Menu(); | ||||
| menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | 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(); | BlockSizeItem *item = new BlockSizeItem(); | ||||
| item->audioInterface = audioInterface; | item->audioInterface = audioInterface; | ||||
| item->blockSize = blockSizes[i]; | item->blockSize = blockSizes[i]; | ||||
| @@ -362,24 +364,14 @@ AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface() | |||||
| box.size = Vec(15*8, 380); | box.size = Vec(15*8, 380); | ||||
| { | { | ||||
| ModulePanel *panel = new ModulePanel(); | |||||
| Panel *panel = new LightPanel(); | |||||
| panel->box.size = box.size; | panel->box.size = box.size; | ||||
| panel->backgroundColor = nvgRGBf(0.90, 0.90, 0.90); | |||||
| // panel->imageFilename = ""; | |||||
| addChild(panel); | addChild(panel); | ||||
| } | } | ||||
| float margin = 5; | float margin = 5; | ||||
| float yPos = margin; | 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 *label = new Label(); | ||||
| label->box.pos = Vec(margin, yPos); | label->box.pos = Vec(margin, yPos); | ||||
| @@ -225,10 +225,8 @@ MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) { | |||||
| box.size = Vec(15*8, 380); | box.size = Vec(15*8, 380); | ||||
| { | { | ||||
| ModulePanel *panel = new ModulePanel(); | |||||
| Panel *panel = new LightPanel(); | |||||
| panel->box.size = box.size; | panel->box.size = box.size; | ||||
| panel->backgroundColor = nvgRGBf(0.90, 0.90, 0.90); | |||||
| // panel->imageFilename = ""; | |||||
| addChild(panel); | addChild(panel); | ||||
| } | } | ||||
| @@ -1,9 +1,6 @@ | |||||
| #include "core.hpp" | #include "core.hpp" | ||||
| using namespace rack; | |||||
| struct CorePlugin : Plugin { | struct CorePlugin : Plugin { | ||||
| CorePlugin() { | CorePlugin() { | ||||
| slug = "Core"; | slug = "Core"; | ||||
| @@ -129,9 +129,9 @@ static void engineRun() { | |||||
| } | } | ||||
| } | } | ||||
| auto end = std::chrono::high_resolution_clock::now(); | 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 | // 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) { | 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()); | fprintf(stderr, "Loaded SVG %s\n", filename.c_str()); | ||||
| } | } | ||||
| else { | else { | ||||
| @@ -324,7 +324,7 @@ SVG::SVG(const std::string &filename) { | |||||
| } | } | ||||
| SVG::~SVG() { | SVG::~SVG() { | ||||
| nsvgDelete(image); | |||||
| nsvgDelete(handle); | |||||
| } | } | ||||
| std::shared_ptr<SVG> SVG::load(const std::string &filename) { | 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 | } // namespace rack | ||||
| @@ -20,7 +20,7 @@ int main() { | |||||
| assert(success); | assert(success); | ||||
| CFRelease(bundleURL); | CFRelease(bundleURL); | ||||
| chdir(dirname(path)); | |||||
| // chdir(dirname(path)); | |||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -4,7 +4,7 @@ | |||||
| namespace rack { | namespace rack { | ||||
| std::string gApplicationName = "VCV Rack"; | std::string gApplicationName = "VCV Rack"; | ||||
| std::string gApplicationVersion = "v0.1.0 alpha"; | |||||
| std::string gApplicationVersion = "v0.2.0 alpha"; | |||||
| RackWidget *gRackWidget = NULL; | RackWidget *gRackWidget = NULL; | ||||
| @@ -7,10 +7,6 @@ namespace rack { | |||||
| #define KNOB_SENSITIVITY 0.001 | #define KNOB_SENSITIVITY 0.001 | ||||
| void Knob::step() { | |||||
| index = eucmod((int) roundf(mapf(value, minValue, maxValue, minIndex, maxIndex)), spriteCount); | |||||
| } | |||||
| void Knob::onDragStart() { | void Knob::onDragStart() { | ||||
| guiCursorLock(); | guiCursorLock(); | ||||
| } | } | ||||
| @@ -3,10 +3,9 @@ | |||||
| namespace rack { | namespace rack { | ||||
| void ModulePanel::draw(NVGcontext *vg) { | |||||
| void Panel::draw(NVGcontext *vg) { | |||||
| nvgBeginPath(vg); | nvgBeginPath(vg); | ||||
| nvgRect(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); | nvgRect(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); | ||||
| NVGpaint paint; | |||||
| // Background color | // Background color | ||||
| nvgFillColor(vg, backgroundColor); | nvgFillColor(vg, backgroundColor); | ||||
| @@ -16,10 +15,15 @@ void ModulePanel::draw(NVGcontext *vg) { | |||||
| if (backgroundImage) { | if (backgroundImage) { | ||||
| int width, height; | int width, height; | ||||
| nvgImageSize(vg, backgroundImage->handle, &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); | nvgFillPaint(vg, paint); | ||||
| nvgFill(vg); | nvgFill(vg); | ||||
| } | } | ||||
| // Border color | |||||
| nvgStrokeColor(vg, borderColor); | |||||
| nvgStrokeWidth(vg, 0.5); | |||||
| nvgStroke(vg); | |||||
| } | } | ||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,4 +1,5 @@ | |||||
| #include "scene.hpp" | #include "scene.hpp" | ||||
| #include "gui.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| @@ -24,5 +25,23 @@ void RackScene::step() { | |||||
| Scene::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 | } // namespace rack | ||||
| @@ -288,23 +288,18 @@ void RackWidget::step() { | |||||
| } | } | ||||
| void RackWidget::draw(NVGcontext *vg) { | void RackWidget::draw(NVGcontext *vg) { | ||||
| // Draw background | |||||
| nvgBeginPath(vg); | nvgBeginPath(vg); | ||||
| nvgRect(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); | 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; | int imageWidth, imageHeight; | ||||
| nvgImageSize(vg, railsImage->handle, &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); | nvgFillPaint(vg, paint); | ||||
| nvgFill(vg); | nvgFill(vg); | ||||
| } | } | ||||
| @@ -4,12 +4,12 @@ | |||||
| namespace rack { | namespace rack { | ||||
| Screw::Screw() { | 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 { | 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); | 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 | // Wire | ||||
| if (opacity > 0.0) { | 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); | nvgMoveTo(vg, pos1.x, pos1.y); | ||||
| nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | ||||
| nvgStrokeColor(vg, colorOutline); | nvgStrokeColor(vg, colorOutline); | ||||
| nvgStrokeWidth(vg, 6); | |||||
| nvgStrokeWidth(vg, 5); | |||||
| nvgStroke(vg); | nvgStroke(vg); | ||||
| // Wire solid | // Wire solid | ||||
| nvgStrokeColor(vg, color); | nvgStrokeColor(vg, color); | ||||
| nvgStrokeWidth(vg, 4); | |||||
| nvgStrokeWidth(vg, 3); | |||||
| nvgStroke(vg); | nvgStroke(vg); | ||||
| nvgRestore(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] = { | 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() { | WireWidget::WireWidget() { | ||||
| wireColorId = (wireColorId + 1) % 8; | |||||
| color = wireColors[wireColorId]; | |||||
| color = wireColors[nextWireColorId]; | |||||
| nextWireColorId = (nextWireColorId + 1) % 8; | |||||
| } | } | ||||
| WireWidget::~WireWidget() { | WireWidget::~WireWidget() { | ||||
| @@ -152,8 +138,11 @@ void WireWidget::draw(NVGcontext *vg) { | |||||
| outputPos = outputPos.minus(absolutePos); | outputPos = outputPos.minus(absolutePos); | ||||
| inputPos = inputPos.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 | } // namespace rack | ||||