| @@ -1,3 +1,6 @@ | |||||
| [submodule "ext/nanovg"] | [submodule "ext/nanovg"] | ||||
| path = ext/nanovg | path = ext/nanovg | ||||
| url = https://github.com/memononen/nanovg.git | url = https://github.com/memononen/nanovg.git | ||||
| [submodule "ext/nanosvg"] | |||||
| path = ext/nanosvg | |||||
| url = https://github.com/memononen/nanosvg.git | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit dc12d90586a8ab99da0c575aafff999666aa5d55 | |||||
| @@ -166,18 +166,18 @@ ParamWidget *createParam(Vec pos, Module *module, int paramId, float minValue, f | |||||
| return param; | return param; | ||||
| } | } | ||||
| inline | |||||
| template <class TInputPort> | |||||
| InputPort *createInput(Vec pos, Module *module, int inputId) { | InputPort *createInput(Vec pos, Module *module, int inputId) { | ||||
| InputPort *port = new InputPort(); | |||||
| InputPort *port = new TInputPort(); | |||||
| port->box.pos = pos; | port->box.pos = pos; | ||||
| port->module = module; | port->module = module; | ||||
| port->inputId = inputId; | port->inputId = inputId; | ||||
| return port; | return port; | ||||
| } | } | ||||
| inline | |||||
| template <class TOutputPort> | |||||
| OutputPort *createOutput(Vec pos, Module *module, int outputId) { | OutputPort *createOutput(Vec pos, Module *module, int outputId) { | ||||
| OutputPort *port = new OutputPort(); | |||||
| OutputPort *port = new TOutputPort(); | |||||
| port->box.pos = pos; | port->box.pos = pos; | ||||
| port->module = module; | port->module = module; | ||||
| port->outputId = outputId; | port->outputId = outputId; | ||||
| @@ -94,7 +94,6 @@ struct RackWidget : OpaqueWidget { | |||||
| struct ModulePanel : TransparentWidget { | struct ModulePanel : TransparentWidget { | ||||
| NVGcolor backgroundColor; | NVGcolor backgroundColor; | ||||
| NVGcolor highlightColor; | |||||
| std::string imageFilename; | std::string imageFilename; | ||||
| void draw(NVGcontext *vg); | void draw(NVGcontext *vg); | ||||
| }; | }; | ||||
| @@ -167,7 +166,7 @@ struct MomentarySwitch : virtual Switch { | |||||
| // ports | // ports | ||||
| //////////////////// | //////////////////// | ||||
| struct Port : OpaqueWidget, SpriteWidget { | |||||
| struct Port : OpaqueWidget { | |||||
| Module *module = NULL; | Module *module = NULL; | ||||
| WireWidget *connectedWire = NULL; | WireWidget *connectedWire = NULL; | ||||
| @@ -175,8 +174,6 @@ struct Port : OpaqueWidget, SpriteWidget { | |||||
| ~Port(); | ~Port(); | ||||
| void disconnect(); | void disconnect(); | ||||
| int type; | |||||
| void drawGlow(NVGcontext *vg); | |||||
| void onMouseDown(int button); | void onMouseDown(int button); | ||||
| void onDragEnd(); | void onDragEnd(); | ||||
| }; | }; | ||||
| @@ -184,7 +181,6 @@ struct Port : OpaqueWidget, SpriteWidget { | |||||
| struct InputPort : Port { | struct InputPort : Port { | ||||
| int inputId; | int inputId; | ||||
| void draw(NVGcontext *vg); | |||||
| void onDragStart(); | void onDragStart(); | ||||
| void onDragDrop(Widget *origin); | void onDragDrop(Widget *origin); | ||||
| }; | }; | ||||
| @@ -192,7 +188,6 @@ struct InputPort : Port { | |||||
| struct OutputPort : Port { | struct OutputPort : Port { | ||||
| int outputId; | int outputId; | ||||
| void draw(NVGcontext *vg); | |||||
| void onDragStart(); | void onDragStart(); | ||||
| void onDragDrop(Widget *origin); | void onDragDrop(Widget *origin); | ||||
| }; | }; | ||||
| @@ -220,5 +215,41 @@ struct Scene : OpaqueWidget { | |||||
| void step(); | void step(); | ||||
| }; | }; | ||||
| //////////////////// | |||||
| // component library | |||||
| //////////////////// | |||||
| struct PJ301M : SpriteWidget { | |||||
| PJ301M() { | |||||
| box.size = Vec(24, 24); | |||||
| spriteOffset = Vec(-10, -10); | |||||
| spriteSize = Vec(48, 48); | |||||
| spriteFilename = "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); | |||||
| spriteFilename = "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); | |||||
| spriteFilename = "res/ComponentLibrary/CL1362.png"; | |||||
| } | |||||
| }; | |||||
| struct InputPortCL1362 : InputPort, CL1362 {}; | |||||
| struct OutputPortCL1362 : OutputPort, CL1362 {}; | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -45,10 +45,11 @@ struct AudioInterface : Module { | |||||
| SampleRateConverter<2> inputSrc; | SampleRateConverter<2> inputSrc; | ||||
| SampleRateConverter<2> outputSrc; | SampleRateConverter<2> outputSrc; | ||||
| // in device's sample rate | |||||
| DoubleRingBuffer<Frame<2>, (1<<15)> inputBuffer; | |||||
| // in rack's sample rate | // in rack's sample rate | ||||
| DoubleRingBuffer<Frame<2>, 32> inputBuffer; | |||||
| DoubleRingBuffer<Frame<2>, (1<<15)> outputBuffer; | DoubleRingBuffer<Frame<2>, (1<<15)> outputBuffer; | ||||
| // in device's sample rate | |||||
| DoubleRingBuffer<Frame<2>, (1<<15)> inputSrcBuffer; | |||||
| AudioInterface(); | AudioInterface(); | ||||
| ~AudioInterface(); | ~AudioInterface(); | ||||
| @@ -89,29 +90,35 @@ void AudioInterface::step() { | |||||
| // Get input and pass it through the sample rate converter | // Get input and pass it through the sample rate converter | ||||
| if (numOutputs > 0) { | if (numOutputs > 0) { | ||||
| Frame<2> f; | |||||
| f.samples[0] = getf(inputs[AUDIO1_INPUT]) / 5.0; | |||||
| f.samples[1] = getf(inputs[AUDIO2_INPUT]) / 5.0; | |||||
| inputSrc.setRatio(sampleRate / gRack->sampleRate); | |||||
| int inLen = 1; | |||||
| int outLen = inputBuffer.capacity(); | |||||
| inputSrc.process((const float*) &f, &inLen, (float*) inputBuffer.endData(), &outLen); | |||||
| inputBuffer.endIncr(outLen); | |||||
| if (!inputBuffer.full()) { | |||||
| Frame<2> f; | |||||
| f.samples[0] = getf(inputs[AUDIO1_INPUT]) / 5.0; | |||||
| f.samples[1] = getf(inputs[AUDIO2_INPUT]) / 5.0; | |||||
| inputBuffer.push(f); | |||||
| } | |||||
| // Once full, sample rate convert the input | |||||
| if (inputBuffer.full()) { | |||||
| inputSrc.setRatio(sampleRate / gRack->sampleRate); | |||||
| int inLen = inputBuffer.size(); | |||||
| int outLen = inputSrcBuffer.capacity(); | |||||
| inputSrc.process((const float*) inputBuffer.startData(), &inLen, (float*) inputSrcBuffer.endData(), &outLen); | |||||
| inputBuffer.startIncr(inLen); | |||||
| inputSrcBuffer.endIncr(outLen); | |||||
| } | |||||
| } | } | ||||
| // Read/write stream if we have enough input | |||||
| bool streamReady = (numOutputs > 0) ? (inputBuffer.size() >= blockSize) : (outputBuffer.empty()); | |||||
| // Read/write stream if we have enough input, OR the output buffer is empty if we have no input | |||||
| bool streamReady = (numOutputs > 0) ? (inputSrcBuffer.size() >= blockSize) : (outputBuffer.empty()); | |||||
| if (streamReady) { | if (streamReady) { | ||||
| // printf("%p\t%d\t%d\n", this, inputSrcBuffer.size(), outputBuffer.size()); | |||||
| PaError err; | PaError err; | ||||
| // Read output from input stream | // Read output from input stream | ||||
| // (for some reason, if you write the output stream before you read the input stream, PortAudio can segfault on Windows.) | // (for some reason, if you write the output stream before you read the input stream, PortAudio can segfault on Windows.) | ||||
| if (numInputs > 0) { | if (numInputs > 0) { | ||||
| Frame<2> *buf = new Frame<2>[blockSize]; | Frame<2> *buf = new Frame<2>[blockSize]; | ||||
| printf("read %d\n", blockSize); | |||||
| err = Pa_ReadStream(stream, (float*) buf, blockSize); | err = Pa_ReadStream(stream, (float*) buf, blockSize); | ||||
| printf("read done\n"); | |||||
| if (err) { | if (err) { | ||||
| // Ignore buffer underflows | // Ignore buffer underflows | ||||
| if (err != paInputOverflowed) { | if (err != paInputOverflowed) { | ||||
| @@ -131,11 +138,9 @@ void AudioInterface::step() { | |||||
| // Write input to output stream | // Write input to output stream | ||||
| if (numOutputs > 0) { | if (numOutputs > 0) { | ||||
| assert(inputBuffer.size() >= blockSize); | |||||
| printf("write %d\n", blockSize); | |||||
| err = Pa_WriteStream(stream, (const float*) inputBuffer.startData(), blockSize); | |||||
| printf("write done\n"); | |||||
| inputBuffer.startIncr(blockSize); | |||||
| assert(inputSrcBuffer.size() >= blockSize); | |||||
| err = Pa_WriteStream(stream, (const float*) inputSrcBuffer.startData(), blockSize); | |||||
| inputSrcBuffer.startIncr(blockSize); | |||||
| if (err) { | if (err) { | ||||
| // Ignore buffer underflows | // Ignore buffer underflows | ||||
| if (err != paOutputUnderflowed) { | if (err != paOutputUnderflowed) { | ||||
| @@ -241,6 +246,7 @@ void AudioInterface::closeDevice() { | |||||
| // Clear buffers | // Clear buffers | ||||
| inputBuffer.clear(); | inputBuffer.clear(); | ||||
| outputBuffer.clear(); | outputBuffer.clear(); | ||||
| inputSrcBuffer.clear(); | |||||
| inputSrc.reset(); | inputSrc.reset(); | ||||
| outputSrc.reset(); | outputSrc.reset(); | ||||
| } | } | ||||
| @@ -355,6 +361,14 @@ struct BlockSizeChoice : ChoiceButton { | |||||
| AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface()) { | AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface()) { | ||||
| box.size = Vec(15*8, 380); | box.size = Vec(15*8, 380); | ||||
| { | |||||
| ModulePanel *panel = new ModulePanel(); | |||||
| panel->box.size = box.size; | |||||
| panel->backgroundColor = nvgRGBf(0.90, 0.90, 0.90); | |||||
| // panel->imageFilename = ""; | |||||
| addChild(panel); | |||||
| } | |||||
| float margin = 5; | float margin = 5; | ||||
| float yPos = margin; | float yPos = margin; | ||||
| @@ -420,8 +434,8 @@ AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface() | |||||
| } | } | ||||
| yPos += 5; | yPos += 5; | ||||
| addInput(createInput(Vec(25, yPos), module, AudioInterface::AUDIO1_INPUT)); | |||||
| addInput(createInput(Vec(75, yPos), module, AudioInterface::AUDIO2_INPUT)); | |||||
| addInput(createInput<InputPortPJ3410>(Vec(20, yPos), module, AudioInterface::AUDIO1_INPUT)); | |||||
| addInput(createInput<InputPortPJ3410>(Vec(70, yPos), module, AudioInterface::AUDIO2_INPUT)); | |||||
| yPos += 35 + margin; | yPos += 35 + margin; | ||||
| { | { | ||||
| @@ -433,12 +447,7 @@ AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface() | |||||
| } | } | ||||
| yPos += 5; | yPos += 5; | ||||
| addOutput(createOutput(Vec(25, yPos), module, AudioInterface::AUDIO1_OUTPUT)); | |||||
| addOutput(createOutput(Vec(75, yPos), module, AudioInterface::AUDIO2_OUTPUT)); | |||||
| addOutput(createOutput<OutputPortPJ3410>(Vec(20, yPos), module, AudioInterface::AUDIO1_OUTPUT)); | |||||
| addOutput(createOutput<OutputPortPJ3410>(Vec(70, yPos), module, AudioInterface::AUDIO2_OUTPUT)); | |||||
| yPos += 35 + margin; | yPos += 35 + margin; | ||||
| } | } | ||||
| void AudioInterfaceWidget::draw(NVGcontext *vg) { | |||||
| bndBackground(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); | |||||
| ModuleWidget::draw(vg); | |||||
| } | |||||
| @@ -224,6 +224,14 @@ struct MidiChoice : ChoiceButton { | |||||
| MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) { | MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) { | ||||
| box.size = Vec(15*8, 380); | box.size = Vec(15*8, 380); | ||||
| { | |||||
| ModulePanel *panel = new ModulePanel(); | |||||
| panel->box.size = box.size; | |||||
| panel->backgroundColor = nvgRGBf(0.90, 0.90, 0.90); | |||||
| // panel->imageFilename = ""; | |||||
| addChild(panel); | |||||
| } | |||||
| float margin = 5; | float margin = 5; | ||||
| float yPos = margin; | float yPos = margin; | ||||
| @@ -246,8 +254,8 @@ MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) { | |||||
| } | } | ||||
| yPos += 5; | yPos += 5; | ||||
| addOutput(createOutput(Vec(25, yPos), module, MidiInterface::PITCH_OUTPUT)); | |||||
| addOutput(createOutput(Vec(75, yPos), module, MidiInterface::GATE_OUTPUT)); | |||||
| addOutput(createOutput<OutputPortPJ3410>(Vec(20, yPos), module, MidiInterface::PITCH_OUTPUT)); | |||||
| addOutput(createOutput<OutputPortPJ3410>(Vec(70, yPos), module, MidiInterface::GATE_OUTPUT)); | |||||
| yPos += 25 + margin; | yPos += 25 + margin; | ||||
| { | { | ||||
| @@ -264,8 +272,3 @@ MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) { | |||||
| yPos += pitchLabel->box.size.y + margin; | yPos += pitchLabel->box.size.y + margin; | ||||
| } | } | ||||
| } | } | ||||
| void MidiInterfaceWidget::draw(NVGcontext *vg) { | |||||
| bndBackground(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); | |||||
| ModuleWidget::draw(vg); | |||||
| } | |||||
| @@ -14,10 +14,8 @@ void midiInit(); | |||||
| struct AudioInterfaceWidget : ModuleWidget { | struct AudioInterfaceWidget : ModuleWidget { | ||||
| AudioInterfaceWidget(); | AudioInterfaceWidget(); | ||||
| void draw(NVGcontext *vg); | |||||
| }; | }; | ||||
| struct MidiInterfaceWidget : ModuleWidget { | struct MidiInterfaceWidget : ModuleWidget { | ||||
| MidiInterfaceWidget(); | MidiInterfaceWidget(); | ||||
| void draw(NVGcontext *vg); | |||||
| }; | }; | ||||
| @@ -3,13 +3,6 @@ | |||||
| namespace rack { | namespace rack { | ||||
| void InputPort::draw(NVGcontext *vg) { | |||||
| SpriteWidget::draw(vg); | |||||
| if (gRackWidget->activeWire && gRackWidget->activeWire->inputPort) { | |||||
| Port::drawGlow(vg); | |||||
| } | |||||
| } | |||||
| void InputPort::onDragStart() { | void InputPort::onDragStart() { | ||||
| if (connectedWire) { | if (connectedWire) { | ||||
| // Disconnect wire from this port, but set it as the active wire | // Disconnect wire from this port, but set it as the active wire | ||||
| @@ -8,12 +8,8 @@ void ModulePanel::draw(NVGcontext *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; | NVGpaint paint; | ||||
| // Background gradient | |||||
| Vec c = box.pos; | |||||
| float length = box.size.norm(); | |||||
| paint = nvgRadialGradient(vg, c.x, c.y, 0.0, length, highlightColor, backgroundColor); | |||||
| nvgFillPaint(vg, paint); | |||||
| // nvgFillColor(vg, backgroundColor); | |||||
| // Background color | |||||
| nvgFillColor(vg, backgroundColor); | |||||
| nvgFill(vg); | nvgFill(vg); | ||||
| // Background image | // Background image | ||||
| @@ -3,13 +3,6 @@ | |||||
| namespace rack { | namespace rack { | ||||
| void OutputPort::draw(NVGcontext *vg) { | |||||
| SpriteWidget::draw(vg); | |||||
| if (gRackWidget->activeWire && gRackWidget->activeWire->outputPort) { | |||||
| Port::drawGlow(vg); | |||||
| } | |||||
| } | |||||
| void OutputPort::onDragStart() { | void OutputPort::onDragStart() { | ||||
| if (connectedWire) { | if (connectedWire) { | ||||
| // Disconnect wire from this port, but set it as the active wire | // Disconnect wire from this port, but set it as the active wire | ||||
| @@ -5,11 +5,6 @@ namespace rack { | |||||
| Port::Port() { | Port::Port() { | ||||
| box.size = Vec(20, 20); | box.size = Vec(20, 20); | ||||
| spriteOffset = Vec(-18, -18); | |||||
| spriteSize = Vec(56, 56); | |||||
| spriteFilename = "res/port.png"; | |||||
| index = randomu32() % 5; | |||||
| } | } | ||||
| Port::~Port() { | Port::~Port() { | ||||
| @@ -24,17 +19,6 @@ void Port::disconnect() { | |||||
| } | } | ||||
| } | } | ||||
| void Port::drawGlow(NVGcontext *vg) { | |||||
| Vec c = box.getCenter(); | |||||
| NVGcolor icol = nvgRGBAf(1, 1, 1, 0.5); | |||||
| NVGcolor ocol = nvgRGBAf(1, 1, 1, 0); | |||||
| NVGpaint paint = nvgRadialGradient(vg, c.x, c.y, 0, 20, icol, ocol); | |||||
| nvgFillPaint(vg, paint); | |||||
| nvgBeginPath(vg); | |||||
| nvgRect(vg, box.pos.x - 10, box.pos.y - 10, box.size.x + 20, box.size.y + 20); | |||||
| nvgFill(vg); | |||||
| } | |||||
| void Port::onMouseDown(int button) { | void Port::onMouseDown(int button) { | ||||
| if (button == 1) { | if (button == 1) { | ||||
| disconnect(); | disconnect(); | ||||
| @@ -3,37 +3,79 @@ | |||||
| namespace rack { | namespace rack { | ||||
| void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, float tension, NVGcolor color) { | |||||
| float dist = pos1.minus(pos2).norm(); | |||||
| Vec slump; | |||||
| slump.y = (1.0 - tension) * (150.0 + 1.0*dist); | |||||
| Vec pos3 = pos1.plus(pos2).div(2).plus(slump); | |||||
| void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, float tension, NVGcolor color, 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) { | |||||
| nvgSave(vg); | |||||
| nvgGlobalAlpha(vg, opacity); | |||||
| float dist = pos1.minus(pos2).norm(); | |||||
| Vec slump; | |||||
| slump.y = (1.0 - tension) * (150.0 + 1.0*dist); | |||||
| Vec pos3 = pos1.plus(pos2).div(2).plus(slump); | |||||
| nvgLineJoin(vg, NVG_ROUND); | |||||
| // Shadow | |||||
| Vec pos4 = pos3.plus(slump.mult(0.08)); | |||||
| nvgBeginPath(vg); | |||||
| nvgMoveTo(vg, pos1.x, pos1.y); | |||||
| nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y); | |||||
| nvgStrokeColor(vg, colorShadow); | |||||
| nvgStrokeWidth(vg, 5); | |||||
| nvgStroke(vg); | |||||
| // Wire outline | |||||
| nvgBeginPath(vg); | |||||
| nvgMoveTo(vg, pos1.x, pos1.y); | |||||
| nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | |||||
| nvgStrokeColor(vg, colorOutline); | |||||
| nvgStrokeWidth(vg, 6); | |||||
| nvgStroke(vg); | |||||
| // Wire solid | |||||
| nvgStrokeColor(vg, color); | |||||
| nvgStrokeWidth(vg, 4); | |||||
| nvgStroke(vg); | |||||
| nvgRestore(vg); | |||||
| } | |||||
| // First plug | |||||
| nvgBeginPath(vg); | |||||
| nvgCircle(vg, pos1.x, pos1.y, 21/2.0); | |||||
| nvgFillColor(vg, colorOutline); | |||||
| nvgFill(vg); | |||||
| nvgLineJoin(vg, NVG_ROUND); | |||||
| nvgBeginPath(vg); | |||||
| nvgCircle(vg, pos1.x, pos1.y, 19/2.0); | |||||
| nvgFillColor(vg, color); | |||||
| nvgFill(vg); | |||||
| // Shadow | |||||
| Vec pos4 = pos3.plus(slump.mult(0.08)); | |||||
| NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.08); | |||||
| nvgBeginPath(vg); | nvgBeginPath(vg); | ||||
| nvgMoveTo(vg, pos1.x, pos1.y); | |||||
| nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y); | |||||
| nvgStrokeColor(vg, colorShadow); | |||||
| nvgStrokeWidth(vg, 5); | |||||
| nvgStroke(vg); | |||||
| // Wire outline | |||||
| NVGcolor colorOutline = nvgRGBf(0, 0, 0); | |||||
| 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); | nvgBeginPath(vg); | ||||
| nvgMoveTo(vg, pos1.x, pos1.y); | |||||
| nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | |||||
| nvgStrokeColor(vg, colorOutline); | |||||
| nvgStrokeWidth(vg, 4); | |||||
| nvgStroke(vg); | |||||
| // Wire solid | |||||
| nvgStrokeColor(vg, color); | |||||
| nvgStrokeWidth(vg, 2); | |||||
| nvgStroke(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); | |||||
| } | } | ||||
| @@ -87,35 +129,29 @@ void WireWidget::updateWire() { | |||||
| void WireWidget::draw(NVGcontext *vg) { | void WireWidget::draw(NVGcontext *vg) { | ||||
| Vec outputPos, inputPos; | Vec outputPos, inputPos; | ||||
| Vec absolutePos = getAbsolutePos(); | Vec absolutePos = getAbsolutePos(); | ||||
| float wireOpacity = gScene->toolbar->wireOpacitySlider->value / 100.0; | |||||
| float opacity = gScene->toolbar->wireOpacitySlider->value / 100.0; | |||||
| // Compute location of pos1 and pos2 | |||||
| if (outputPort) { | if (outputPort) { | ||||
| outputPos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter(); | outputPos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter(); | ||||
| } | } | ||||
| else { | else { | ||||
| outputPos = gMousePos; | outputPos = gMousePos; | ||||
| wireOpacity = 1.0; | |||||
| opacity = 1.0; | |||||
| } | } | ||||
| if (inputPort) { | if (inputPort) { | ||||
| inputPos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter(); | inputPos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter(); | ||||
| } | } | ||||
| else { | else { | ||||
| inputPos = gMousePos; | inputPos = gMousePos; | ||||
| wireOpacity = 1.0; | |||||
| opacity = 1.0; | |||||
| } | } | ||||
| outputPos = outputPos.minus(absolutePos); | outputPos = outputPos.minus(absolutePos); | ||||
| inputPos = inputPos.minus(absolutePos); | inputPos = inputPos.minus(absolutePos); | ||||
| bndNodePort(vg, outputPos.x, outputPos.y, BND_DEFAULT, color); | |||||
| bndNodePort(vg, inputPos.x, inputPos.y, BND_DEFAULT, color); | |||||
| nvgSave(vg); | |||||
| if (wireOpacity > 0.0) { | |||||
| nvgGlobalAlpha(vg, wireOpacity); | |||||
| float tension = gScene->toolbar->wireTensionSlider->value; | |||||
| drawWire(vg, outputPos, inputPos, tension, color); | |||||
| } | |||||
| nvgRestore(vg); | |||||
| float tension = gScene->toolbar->wireTensionSlider->value; | |||||
| drawWire(vg, outputPos, inputPos, tension, color, opacity); | |||||
| } | } | ||||