@@ -277,6 +277,33 @@ struct MomentarySwitch : virtual Switch { | |||||
} | } | ||||
}; | }; | ||||
//////////////////// | |||||
// lights | |||||
//////////////////// | |||||
struct LightWidget : TransparentWidget { | |||||
NVGcolor bgColor = nvgRGBf(0, 0, 0); | |||||
NVGcolor color = nvgRGBf(1, 1, 1); | |||||
void draw(NVGcontext *vg) override; | |||||
}; | |||||
/** Mixes a list of colors based on a list of brightness values */ | |||||
struct MultiLightWidget : LightWidget { | |||||
std::vector<NVGcolor> baseColors; | |||||
void addBaseColor(NVGcolor baseColor); | |||||
/** Sets the color to a linear combination of the baseColors with the given weights */ | |||||
void setValues(const std::vector<float> &values); | |||||
}; | |||||
/** A MultiLightWidget that points to a module's Light or a range of lights | |||||
Will access firstLightId, firstLightId + 1, etc. for each added color | |||||
*/ | |||||
struct ModuleLightWidget : MultiLightWidget { | |||||
Module *module = NULL; | |||||
int firstLightId; | |||||
void step() override; | |||||
}; | |||||
//////////////////// | //////////////////// | ||||
// ports | // ports | ||||
//////////////////// | //////////////////// | ||||
@@ -290,8 +317,11 @@ struct Port : OpaqueWidget { | |||||
Module *module = NULL; | Module *module = NULL; | ||||
PortType type = INPUT; | PortType type = INPUT; | ||||
int portId; | int portId; | ||||
MultiLightWidget *plugLight; | |||||
Port(); | |||||
~Port(); | ~Port(); | ||||
void step() override; | |||||
void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
void onMouseDown(EventMouseDown &e) override; | void onMouseDown(EventMouseDown &e) override; | ||||
void onDragStart(EventDragStart &e) override; | void onDragStart(EventDragStart &e) override; | ||||
@@ -315,29 +345,6 @@ struct SVGScrew : FramebufferWidget { | |||||
SVGScrew(); | SVGScrew(); | ||||
}; | }; | ||||
//////////////////// | |||||
// lights | |||||
//////////////////// | |||||
struct LightWidget : TransparentWidget { | |||||
NVGcolor bgColor = nvgRGBf(0, 0, 0); | |||||
NVGcolor color = nvgRGBf(1, 1, 1); | |||||
void draw(NVGcontext *vg) override; | |||||
}; | |||||
/** A LightWidget that points to a module's Light or a range of lights */ | |||||
struct ModuleLightWidget : LightWidget { | |||||
Module *module = NULL; | |||||
int lightId; | |||||
}; | |||||
/** Mixes colors based on the brightness of the module light at lightId, lightId + 1, etc */ | |||||
struct ColorLightWidget : ModuleLightWidget { | |||||
std::vector<NVGcolor> colors; | |||||
void addColor(NVGcolor c); | |||||
void step() override; | |||||
}; | |||||
//////////////////// | //////////////////// | ||||
// scene | // scene | ||||
//////////////////// | //////////////////// | ||||
@@ -347,7 +354,6 @@ struct Toolbar : OpaqueWidget { | |||||
Slider *wireTensionSlider; | Slider *wireTensionSlider; | ||||
Slider *zoomSlider; | Slider *zoomSlider; | ||||
RadioButton *cpuUsageButton; | RadioButton *cpuUsageButton; | ||||
RadioButton *plugLightButton; | |||||
Toolbar(); | Toolbar(); | ||||
void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
@@ -368,43 +368,43 @@ struct CL1362Port : SVGPort { | |||||
// Lights | // Lights | ||||
//////////////////// | //////////////////// | ||||
struct RedLight : ColorLightWidget { | |||||
struct RedLight : ModuleLightWidget { | |||||
RedLight() { | RedLight() { | ||||
addColor(COLOR_RED); | |||||
addBaseColor(COLOR_RED); | |||||
} | } | ||||
}; | }; | ||||
struct GreenLight : ColorLightWidget { | |||||
struct GreenLight : ModuleLightWidget { | |||||
GreenLight() { | GreenLight() { | ||||
addColor(COLOR_GREEN); | |||||
addBaseColor(COLOR_GREEN); | |||||
} | } | ||||
}; | }; | ||||
struct YellowLight : ColorLightWidget { | |||||
struct YellowLight : ModuleLightWidget { | |||||
YellowLight() { | YellowLight() { | ||||
addColor(COLOR_YELLOW); | |||||
addBaseColor(COLOR_YELLOW); | |||||
} | } | ||||
}; | }; | ||||
struct BlueLight : ColorLightWidget { | |||||
struct BlueLight : ModuleLightWidget { | |||||
BlueLight() { | BlueLight() { | ||||
addColor(COLOR_BLUE); | |||||
addBaseColor(COLOR_BLUE); | |||||
} | } | ||||
}; | }; | ||||
/** Reads two adjacent lightIds, so `lightId` and `lightId + 1` must be defined */ | /** Reads two adjacent lightIds, so `lightId` and `lightId + 1` must be defined */ | ||||
struct GreenRedLight : ColorLightWidget { | |||||
struct GreenRedLight : ModuleLightWidget { | |||||
GreenRedLight() { | GreenRedLight() { | ||||
addColor(COLOR_GREEN); | |||||
addColor(COLOR_RED); | |||||
addBaseColor(COLOR_GREEN); | |||||
addBaseColor(COLOR_RED); | |||||
} | } | ||||
}; | }; | ||||
struct RedGreenBlueLight : ColorLightWidget { | |||||
struct RedGreenBlueLight : ModuleLightWidget { | |||||
RedGreenBlueLight() { | RedGreenBlueLight() { | ||||
addColor(COLOR_RED); | |||||
addColor(COLOR_GREEN); | |||||
addColor(COLOR_BLUE); | |||||
addBaseColor(COLOR_RED); | |||||
addBaseColor(COLOR_GREEN); | |||||
addBaseColor(COLOR_BLUE); | |||||
} | } | ||||
}; | }; | ||||
@@ -11,11 +11,22 @@ struct Param { | |||||
float value = 0.0; | float value = 0.0; | ||||
}; | }; | ||||
struct Light { | |||||
/** The square of the brightness value */ | |||||
float value = 0.0; | |||||
float getBrightness(); | |||||
void setBrightness(float brightness) { | |||||
value = brightness * brightness; | |||||
} | |||||
void setBrightnessSmooth(float brightness); | |||||
}; | |||||
struct Input { | struct Input { | ||||
/** Voltage of the port, zero if not plugged in. Read-only by Module */ | /** Voltage of the port, zero if not plugged in. Read-only by Module */ | ||||
float value = 0.0; | float value = 0.0; | ||||
/** Whether a wire is plugged in */ | /** Whether a wire is plugged in */ | ||||
bool active = false; | bool active = false; | ||||
Light plugLights[2]; | |||||
/** Returns the value if a wire is plugged in, otherwise returns the given default value */ | /** Returns the value if a wire is plugged in, otherwise returns the given default value */ | ||||
float normalize(float normalValue) { | float normalize(float normalValue) { | ||||
return active ? value : normalValue; | return active ? value : normalValue; | ||||
@@ -27,16 +38,7 @@ struct Output { | |||||
float value = 0.0; | float value = 0.0; | ||||
/** Whether a wire is plugged in */ | /** Whether a wire is plugged in */ | ||||
bool active = false; | bool active = false; | ||||
}; | |||||
struct Light { | |||||
/** The square of the brightness value */ | |||||
float value = 0.0; | |||||
float getBrightness(); | |||||
void setBrightness(float brightness) { | |||||
value = brightness * brightness; | |||||
} | |||||
void setBrightnessSmooth(float brightness); | |||||
Light plugLights[2]; | |||||
}; | }; | ||||
@@ -49,7 +51,7 @@ struct Module { | |||||
float cpuTime = 0.0; | float cpuTime = 0.0; | ||||
/** Deprecated, use constructor below this one */ | /** Deprecated, use constructor below this one */ | ||||
Module() {} | |||||
Module() DEPRECATED {} | |||||
/** Constructs Module with a fixed number of params, inputs, and outputs */ | /** Constructs Module with a fixed number of params, inputs, and outputs */ | ||||
Module(int numParams, int numInputs, int numOutputs, int numLights = 0) { | Module(int numParams, int numInputs, int numOutputs, int numLights = 0) { | ||||
params.resize(numParams); | params.resize(numParams); | ||||
@@ -74,11 +74,11 @@ Port *createOutput(Vec pos, Module *module, int outputId) { | |||||
} | } | ||||
template<class TModuleLightWidget> | template<class TModuleLightWidget> | ||||
ModuleLightWidget *createLight(Vec pos, Module *module, int lightId) { | |||||
ModuleLightWidget *createLight(Vec pos, Module *module, int firstLightId) { | |||||
ModuleLightWidget *light = new TModuleLightWidget(); | ModuleLightWidget *light = new TModuleLightWidget(); | ||||
light->box.pos = pos; | light->box.pos = pos; | ||||
light->module = module; | light->module = module; | ||||
light->lightId = lightId; | |||||
light->firstLightId = firstLightId; | |||||
return light; | return light; | ||||
} | } | ||||
@@ -1,27 +0,0 @@ | |||||
#include "app.hpp" | |||||
#include "engine.hpp" | |||||
namespace rack { | |||||
void ColorLightWidget::addColor(NVGcolor c) { | |||||
colors.push_back(c); | |||||
} | |||||
void ColorLightWidget::step() { | |||||
assert(module); | |||||
assert(module->lights.size() >= lightId + colors.size()); | |||||
color = nvgRGBf(0, 0, 0); | |||||
for (int i = 0; i < (int)colors.size(); i++) { | |||||
NVGcolor c = colors[i]; | |||||
float brightness = module->lights[lightId + i].getBrightness(); | |||||
brightness = clampf(brightness, 0.0, 1.0); | |||||
color.r += c.r * brightness; | |||||
color.g += c.g * brightness; | |||||
color.b += c.b * brightness; | |||||
} | |||||
} | |||||
} // namespace rack |
@@ -0,0 +1,22 @@ | |||||
#include "app.hpp" | |||||
#include "engine.hpp" | |||||
namespace rack { | |||||
void ModuleLightWidget::step() { | |||||
assert(module); | |||||
assert(module->lights.size() >= firstLightId + baseColors.size()); | |||||
std::vector<float> values(baseColors.size()); | |||||
for (size_t i = 0; i < baseColors.size(); i++) { | |||||
float value = module->lights[firstLightId + i].getBrightness(); | |||||
value = clampf(value, 0.0, 1.0); | |||||
values[i] = value; | |||||
} | |||||
setValues(values); | |||||
} | |||||
} // namespace rack |
@@ -0,0 +1,24 @@ | |||||
#include "app.hpp" | |||||
namespace rack { | |||||
void MultiLightWidget::addBaseColor(NVGcolor baseColor) { | |||||
baseColors.push_back(baseColor); | |||||
} | |||||
void MultiLightWidget::setValues(const std::vector<float> &values) { | |||||
assert(values.size() == baseColors.size()); | |||||
color = nvgRGBf(0, 0, 0); | |||||
for (size_t i = 0; i < baseColors.size(); i++) { | |||||
NVGcolor c = baseColors[i]; | |||||
float value = values[i]; | |||||
color.r += c.r * value; | |||||
color.g += c.g * value; | |||||
color.b += c.b * value; | |||||
} | |||||
} | |||||
} // namespace rack |
@@ -1,13 +1,45 @@ | |||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "gui.hpp" | #include "gui.hpp" | ||||
#include "components.hpp" | |||||
#include "engine.hpp" | |||||
namespace rack { | namespace rack { | ||||
struct PlugLight : MultiLightWidget { | |||||
PlugLight() { | |||||
addBaseColor(COLOR_GREEN); | |||||
addBaseColor(COLOR_RED); | |||||
box.size = Vec(8, 8); | |||||
bgColor = COLOR_BLACK_TRANSPARENT; | |||||
} | |||||
}; | |||||
Port::Port() { | |||||
plugLight = new PlugLight(); | |||||
} | |||||
Port::~Port() { | Port::~Port() { | ||||
// plugLight is not a child and is thus owned by the Port, so we need to delete it here | |||||
delete plugLight; | |||||
gRackWidget->wireContainer->removeAllWires(this); | gRackWidget->wireContainer->removeAllWires(this); | ||||
} | } | ||||
void Port::step() { | |||||
std::vector<float> values(2); | |||||
if (type == INPUT) { | |||||
values[0] = module->inputs[portId].plugLights[0].getBrightness(); | |||||
values[1] = module->inputs[portId].plugLights[1].getBrightness(); | |||||
} | |||||
else { | |||||
values[0] = module->outputs[portId].plugLights[0].getBrightness(); | |||||
values[1] = module->outputs[portId].plugLights[1].getBrightness(); | |||||
} | |||||
plugLight->setValues(values); | |||||
} | |||||
void Port::draw(NVGcontext *vg) { | void Port::draw(NVGcontext *vg) { | ||||
WireWidget *activeWire = gRackWidget->wireContainer->activeWire; | WireWidget *activeWire = gRackWidget->wireContainer->activeWire; | ||||
if (activeWire) { | if (activeWire) { | ||||
@@ -166,16 +166,6 @@ Toolbar::Toolbar() { | |||||
} | } | ||||
xPos += margin; | xPos += margin; | ||||
{ | |||||
plugLightButton = new RadioButton(); | |||||
plugLightButton->box.pos = Vec(xPos, margin); | |||||
plugLightButton->box.size.x = 100; | |||||
plugLightButton->label = "Plug lights"; | |||||
addChild(plugLightButton); | |||||
xPos += plugLightButton->box.size.x; | |||||
} | |||||
xPos += margin; | |||||
/* | /* | ||||
{ | { | ||||
cpuUsageButton = new RadioButton(); | cpuUsageButton = new RadioButton(); | ||||
@@ -155,7 +155,9 @@ void WireWidget::draw(NVGcontext *vg) { | |||||
if (!(inputPort && outputPort)) | if (!(inputPort && outputPort)) | ||||
opacity = 1.0; | opacity = 1.0; | ||||
drawWire(vg, getOutputPos(), getInputPos(), color, tension, opacity); | |||||
Vec outputPos = getOutputPos(); | |||||
Vec inputPos = getInputPos(); | |||||
drawWire(vg, outputPos, inputPos, color, tension, opacity); | |||||
} | } | ||||
void WireWidget::drawPlugs(NVGcontext *vg) { | void WireWidget::drawPlugs(NVGcontext *vg) { | ||||
@@ -166,31 +168,20 @@ void WireWidget::drawPlugs(NVGcontext *vg) { | |||||
drawPlug(vg, inputPos, color); | drawPlug(vg, inputPos, color); | ||||
// Draw plug light | // Draw plug light | ||||
/* | |||||
if (gToolbar->plugLightButton->value > 0.0) { | |||||
if (wire) { | |||||
Output &output = wire->outputModule->outputs[wire->outputId]; | |||||
float value = output.value / 8.0; | |||||
outputLight->box.size = Vec(10, 10); | |||||
inputLight->box.size = Vec(10, 10); | |||||
outputLight->box.pos = outputPos.minus(Vec(5, 5)); | |||||
inputLight->box.pos = inputPos.minus(Vec(5, 5)); | |||||
outputLight->setValue(value); | |||||
inputLight->setValue(value); | |||||
} | |||||
else { | |||||
outputLight->setValue(0.0); | |||||
inputLight->setValue(0.0); | |||||
} | |||||
outputLight->visible = true; | |||||
inputLight->visible = true; | |||||
// TODO | |||||
// Only draw this when light is on top of the plug stack | |||||
if (outputPort) { | |||||
nvgSave(vg); | |||||
nvgTranslate(vg, outputPos.x - 4, outputPos.y - 4); | |||||
outputPort->plugLight->draw(vg); | |||||
nvgRestore(vg); | |||||
} | } | ||||
else { | |||||
outputLight->visible = false; | |||||
inputLight->visible = false; | |||||
if (inputPort) { | |||||
nvgSave(vg); | |||||
nvgTranslate(vg, inputPos.x - 4, inputPos.y - 4); | |||||
inputPort->plugLight->draw(vg); | |||||
nvgRestore(vg); | |||||
} | } | ||||
*/ | |||||
Widget::draw(vg); | |||||
} | } | ||||
@@ -39,7 +39,7 @@ float Light::getBrightness() { | |||||
} | } | ||||
void Light::setBrightnessSmooth(float brightness) { | void Light::setBrightnessSmooth(float brightness) { | ||||
float v = brightness * brightness; | |||||
float v = (brightness > 0.0) ? brightness * brightness : 0.0; | |||||
if (v < value) { | if (v < value) { | ||||
// Fade out light with lambda = 2 * framerate | // Fade out light with lambda = 2 * framerate | ||||
value += (v - value) * sampleTime * (60.0 * 2.0); | value += (v - value) * sampleTime * (60.0 * 2.0); | ||||
@@ -87,6 +87,23 @@ static void engineStep() { | |||||
// Step modules | // Step modules | ||||
for (Module *module : modules) { | for (Module *module : modules) { | ||||
module->step(); | module->step(); | ||||
// TODO skip this step when plug lights are disabled | |||||
// Step ports | |||||
for (Input &input : module->inputs) { | |||||
if (input.active) { | |||||
float value = input.value / 10.0; | |||||
input.plugLights[0].setBrightnessSmooth(value); | |||||
input.plugLights[1].setBrightnessSmooth(-value); | |||||
} | |||||
} | |||||
for (Output &output : module->outputs) { | |||||
if (output.active) { | |||||
float value = output.value / 10.0; | |||||
output.plugLights[0].setBrightnessSmooth(value); | |||||
output.plugLights[1].setBrightnessSmooth(-value); | |||||
} | |||||
} | |||||
} | } | ||||
// Step cables by moving their output values to inputs | // Step cables by moving their output values to inputs | ||||
@@ -52,10 +52,6 @@ static json_t *settingsToJson() { | |||||
json_t *sampleRateJ = json_real(engineGetSampleRate()); | json_t *sampleRateJ = json_real(engineGetSampleRate()); | ||||
json_object_set_new(rootJ, "sampleRate", sampleRateJ); | json_object_set_new(rootJ, "sampleRate", sampleRateJ); | ||||
// plugLight | |||||
json_t *plugLightJ = json_boolean(gToolbar->plugLightButton->value > 0.0); | |||||
json_object_set_new(rootJ, "plugLight", plugLightJ); | |||||
// lastPath | // lastPath | ||||
json_t *lastPathJ = json_string(gRackWidget->lastPath.c_str()); | json_t *lastPathJ = json_string(gRackWidget->lastPath.c_str()); | ||||
json_object_set_new(rootJ, "lastPath", lastPathJ); | json_object_set_new(rootJ, "lastPath", lastPathJ); | ||||
@@ -114,11 +110,6 @@ static void settingsFromJson(json_t *rootJ) { | |||||
engineSetSampleRate(sampleRate); | engineSetSampleRate(sampleRate); | ||||
} | } | ||||
// plugLight | |||||
json_t *plugLightJ = json_object_get(rootJ, "plugLight"); | |||||
if (plugLightJ) | |||||
gToolbar->plugLightButton->setValue(json_is_true(plugLightJ) ? 1.0 : 0.0); | |||||
// lastPath | // lastPath | ||||
json_t *lastPathJ = json_object_get(rootJ, "lastPath"); | json_t *lastPathJ = json_object_get(rootJ, "lastPath"); | ||||
if (lastPathJ) | if (lastPathJ) | ||||