You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
4.8KB

  1. #include "app.hpp"
  2. #include "engine.hpp"
  3. #include "components.hpp"
  4. namespace rack {
  5. static void drawPlug(NVGcontext *vg, Vec pos, NVGcolor color) {
  6. NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5);
  7. // Plug solid
  8. nvgBeginPath(vg);
  9. nvgCircle(vg, pos.x, pos.y, 9);
  10. nvgFillColor(vg, color);
  11. nvgFill(vg);
  12. // Border
  13. nvgStrokeWidth(vg, 1.0);
  14. nvgStrokeColor(vg, colorOutline);
  15. nvgStroke(vg);
  16. // Hole
  17. nvgBeginPath(vg);
  18. nvgCircle(vg, pos.x, pos.y, 5);
  19. nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0));
  20. nvgFill(vg);
  21. }
  22. static void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, NVGcolor color, float tension, float opacity) {
  23. NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.08);
  24. NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5);
  25. // Wire
  26. if (opacity > 0.0) {
  27. nvgSave(vg);
  28. nvgGlobalAlpha(vg, powf(opacity, 1.5));
  29. float dist = pos1.minus(pos2).norm();
  30. Vec slump;
  31. slump.y = (1.0 - tension) * (150.0 + 1.0*dist);
  32. Vec pos3 = pos1.plus(pos2).div(2).plus(slump);
  33. nvgLineJoin(vg, NVG_ROUND);
  34. // Shadow
  35. Vec pos4 = pos3.plus(slump.mult(0.08));
  36. nvgBeginPath(vg);
  37. nvgMoveTo(vg, pos1.x, pos1.y);
  38. nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y);
  39. nvgStrokeColor(vg, colorShadow);
  40. nvgStrokeWidth(vg, 5);
  41. nvgStroke(vg);
  42. // Wire outline
  43. nvgBeginPath(vg);
  44. nvgMoveTo(vg, pos1.x, pos1.y);
  45. nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y);
  46. nvgStrokeColor(vg, colorOutline);
  47. nvgStrokeWidth(vg, 5);
  48. nvgStroke(vg);
  49. // Wire solid
  50. nvgStrokeColor(vg, color);
  51. nvgStrokeWidth(vg, 3);
  52. nvgStroke(vg);
  53. nvgRestore(vg);
  54. }
  55. }
  56. static const NVGcolor wireColors[6] = {
  57. nvgRGB(0xc9, 0xb7, 0x0e), // yellow
  58. nvgRGB(0xc9, 0x18, 0x47), // red
  59. nvgRGB(0x0c, 0x8e, 0x15), // green
  60. nvgRGB(0x09, 0x86, 0xad), // blue
  61. nvgRGB(0x44, 0x44, 0x44), // black
  62. // nvgRGB(0x66, 0x66, 0x66), // gray
  63. // nvgRGB(0x88, 0x88, 0x88), // light gray
  64. nvgRGB(0xaa, 0xaa, 0xaa), // white
  65. };
  66. static int lastWireColorId = -1;
  67. WireWidget::WireWidget() {
  68. lastWireColorId = (lastWireColorId + 1) % 6;
  69. color = wireColors[lastWireColorId];
  70. inputLight = construct<PolarityLight>(&PolarityLight::posColor, COLOR_GREEN, &PolarityLight::negColor, COLOR_RED);
  71. outputLight = construct<PolarityLight>(&PolarityLight::posColor, COLOR_GREEN, &PolarityLight::negColor, COLOR_RED);
  72. addChild(inputLight);
  73. addChild(outputLight);
  74. }
  75. WireWidget::~WireWidget() {
  76. outputPort = NULL;
  77. inputPort = NULL;
  78. updateWire();
  79. }
  80. void WireWidget::updateWire() {
  81. if (inputPort && outputPort) {
  82. // Check correct types
  83. assert(inputPort->type == Port::INPUT);
  84. assert(outputPort->type == Port::OUTPUT);
  85. if (!wire) {
  86. wire = new Wire();
  87. wire->outputModule = outputPort->module;
  88. wire->outputId = outputPort->portId;
  89. wire->inputModule = inputPort->module;
  90. wire->inputId = inputPort->portId;
  91. engineAddWire(wire);
  92. }
  93. }
  94. else {
  95. if (wire) {
  96. engineRemoveWire(wire);
  97. delete wire;
  98. wire = NULL;
  99. }
  100. }
  101. }
  102. Vec WireWidget::getOutputPos() {
  103. Vec pos;
  104. if (outputPort) {
  105. pos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter();
  106. }
  107. else if (hoveredOutputPort) {
  108. pos = Rect(hoveredOutputPort->getAbsolutePos(), hoveredOutputPort->box.size).getCenter();
  109. }
  110. else {
  111. pos = gMousePos;
  112. }
  113. return pos.minus(getAbsolutePos().minus(box.pos));
  114. }
  115. Vec WireWidget::getInputPos() {
  116. Vec pos;
  117. if (inputPort) {
  118. pos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter();
  119. }
  120. else if (hoveredInputPort) {
  121. pos = Rect(hoveredInputPort->getAbsolutePos(), hoveredInputPort->box.size).getCenter();
  122. }
  123. else {
  124. pos = gMousePos;
  125. }
  126. return pos.minus(getAbsolutePos().minus(box.pos));
  127. }
  128. void WireWidget::draw(NVGcontext *vg) {
  129. float opacity = gToolbar->wireOpacitySlider->value / 100.0;
  130. float tension = gToolbar->wireTensionSlider->value;
  131. // Draw as opaque if an "incomplete" wire
  132. if (!(inputPort && outputPort))
  133. opacity = 1.0;
  134. drawWire(vg, getOutputPos(), getInputPos(), color, tension, opacity);
  135. }
  136. void WireWidget::drawPlugs(NVGcontext *vg) {
  137. // TODO Figure out a way to draw plugs first and wires last, and cut the plug portion of the wire off.
  138. Vec outputPos = getOutputPos();
  139. Vec inputPos = getInputPos();
  140. drawPlug(vg, outputPos, color);
  141. drawPlug(vg, inputPos, color);
  142. // Draw plug light
  143. if (gToolbar->plugLightButton->value > 0.0) {
  144. if (wire) {
  145. Output &output = wire->outputModule->outputs[wire->outputId];
  146. float value = output.value / 8.0;
  147. outputLight->box.size = Vec(10, 10);
  148. inputLight->box.size = Vec(10, 10);
  149. outputLight->box.pos = outputPos.minus(Vec(5, 5));
  150. inputLight->box.pos = inputPos.minus(Vec(5, 5));
  151. outputLight->setValue(value);
  152. inputLight->setValue(value);
  153. }
  154. else {
  155. outputLight->setValue(0.0);
  156. inputLight->setValue(0.0);
  157. }
  158. outputLight->visible = true;
  159. inputLight->visible = true;
  160. }
  161. else {
  162. outputLight->visible = false;
  163. inputLight->visible = false;
  164. }
  165. Widget::draw(vg);
  166. }
  167. } // namespace rack